////////////////////////////////////////////////////////////////////////////////////////////////////


#include "CLevelEditor.h"
#include "CUserInterface.h"
#include "CAxisControl.h"
#include "CFaceControl.h"
#include "CPlaneControl.h"
#include "CPlaneCamera.h"
#include "CMayaCameraAnimator.h"
#include "CtrolPointCamera.h"
#include "CMoveCommand.h"
#include "CMultiCommand.h"
#include "CScaleCommand.h"
#include "CRotateCommand.h"
#include "CEmptyCommand.h"
#include "CSetIntAttributeCommand.h"
#include "CDeselectCommand.h"
#include "CDeleteCommand.h"
#include "CLinkRoomCommand.h"
#include "CGUITreeCtrl.h"
#include "CRotationControl.h"
#include "IDoUndoCommand.h"
#include "CMultiCommand.h"
//#include "CColladaDatabase.h"
#include "CListBox.h"
#include "PhysicalWorld.h"
#include "CGridSceneNode.h"
#include "CEventReceiver.h"
#include "CEffect.h"
#include "CProperty.h"
#include "CSceneObject.h"
#include "IFileSystem.h"
#include "IXMLWriter.h"
#include "IGUIEnvironment.h"
#include "IGUIContextMenu.h"
#include "IGUIButton.h"
#include "IGUIWindow.h"
#include "IGUIFont.h"
#include "SMesh.h"
#include "IMesh.h"
#include "IrrlichtDevice.h"
#include "ICameraSceneNode.h"

#include <windows.h> 
#include <shellapi.h> 


#include "FpsCommonGLMaterialRenderer.h"
#include "FpsColladaDatabase.h"
#include "FpsSceneManager.h"
#include "Utils\Utils.h"
#include "ISceneNodeAnimatorCameraFPS.h"
//#include "IColladaSceneNodeAnimator.h"
//#include "CColladaCameraSceneNode.h"
#include "CFPSSceneCollisionManager.h"
//#include "CColladaMeshSceneNode.h"
//#include "IColladaMesh.h"
//#include "CColladaMesh.h"
#include "ChangeCameraAnimator.h"
#include "CinematicCamera.h"
#include "CCinematicCommand.h"
#include "CCinematicThread.h"
#include "IGUICheckBox.h"
#include "CameraArea.h"
#include "Lib2D/SpriteManager.h"
#include "Lib2D/Sprite.h"
#include "Common/LevelResource.h"

bool project3DTo2D (vector3df pt, vector2df* result, ICameraSceneNode* camera = 0);

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
#define EDIT_EXTERNAL_SCENES 0
#define NR_HISTORY_AUTOSAVE 100

extern CUserInterface* ui;

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
CLevelEditor::CLevelEditor()
{
	m_bModified = false;
	m_LastFocusedNode = 0;
	m_SelectedNode = 0;
	m_SelectedNodePos = vector3df(0, 0, 0);
	m_SelectedNodeRot = quaternion();
	m_SelectedNodeScale = vector3df(1.0, 1.0, 1.0);
	m_SelectedMousePos = position2di(0, 0);
	m_GameObjects.clear();
	m_camCtrlPointTemplate = 0;
	m_restorePointTemplate = 0;
	m_effectTemplate = 0;
	m_SceneFileName = L"";
	m_editorPath = g->device->getFileSystem()->getWorkingDirectory();
	m_SceneFilePath = g->device->getFileSystem()->getAbsolutePath(g->device->getFileSystem()->getWorkingDirectory());

	g->device->getFileSystem()->addFolderFileArchive((m_editorPath+"\\..\\..\\..\\data\\game\\entities\\textures").c_str());

	m_GameLists.clear();
	//m_TreeList.clear();

	//m_pCollisionTriSelector = NULL;

	m_SaveLoadProgressDraw = false;
	m_SaveLoadProgress = 0;

	//m_HasActiveZone = false;
	
	updateEditorCaption();

	m_bPositionObjOnInsert = false;
	m_bLinkRoomMode = false;

	m_minId = 0;
	m_maxId = 10000;

	m_LastCreatedObjID = -1;

	m_buildDataPath = "..\\..\\..\\data\\build.bat";
	m_launchEmuPath = "..\\..\\..\\build\\win32\\Spiderman_Debug.exe";
	
	m_physicalWorld = new CPhysicalWorld();

	m_isPlayingCinematic = false;
	m_isCinematicPause = false;
	m_isCinematicStepOneFrame = false;
	m_isMovingObject = false;

	m_ckb_cpycam_pos = 0;
	m_ckb_cpycam_cam = 0;
	m_ckb_cpycam_target = 0;

	// initialize skill ID list, in game only use the first number as a ID
	// string here for GD to select more clearly
	m_skillList.Items.push_back(L"0 ultimate");
	m_skillList.Items.push_back(L"1 sense");	
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
CLevelEditor::~CLevelEditor()
{
	CSpriteManager::instance()->UnloadAll();
	CSpriteManager::deleteInstance();

	u32 i;

	for (i = 0; i < m_SceneObjects.size(); i ++)
		if (m_SceneObjects[i])
		{
			delete m_SceneObjects[i];
			m_SceneObjects[i] = 0;
		}
	m_SceneObjects.clear();

	for (i = 0; i <	m_GameObjects.size(); i ++)
		if (m_GameObjects[i])
		{
			delete m_GameObjects[i];
			m_GameObjects[i] = 0;
		}

	m_GameObjects.clear();

	for (i = 0; i < m_Effects.size(); i ++)
		if (m_Effects[i])
		{
			delete m_Effects[i];
			m_Effects[i] = 0;
		}
	m_Effects.clear();
	
	delete m_physicalWorld;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::updateEditorCaption()
{	
	stringw caption = L"LevelEditor - ";
	
	if (!m_SceneFileName.size())
		caption += L"Untitled.irr";
	else
		caption += m_SceneFileName.c_str();

	g->device->setWindowCaption(caption.c_str());
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
ESCENE_NODE_TYPE CLevelEditor::getObjectType(stringw typeStr)
{	

	if (typeStr == L"empty")
		return ESNT_EMPTY;

	if (typeStr == L"skybox")
		return ESNT_SKY_BOX;

	//if (typeStr == L"collada")
	//	return ESNT_COLLADA_ROOT;

	if (typeStr == L"cube")
		return ESNT_CUBE;


	return ESNT_UNKNOWN;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
int CLevelEditor::readConfigOptions()
{
	DEBUG_OUT("reading editor config!!!\n");

	IXMLReader* xml = g->device->getFileSystem()->createXMLReader("editor_config.xml");

	if (!xml)
	{
		g->guienv->addMessageBox(L"Error!", L"Cannot load configuration file!");
		return 1;
	}

	while (xml->read())
	{
		switch(xml->getNodeType())
		{
			case EXN_ELEMENT:
			{
				if (!wcscmp(L"lastFolder", xml->getNodeName()))
				{
					core::stringc lastFolder = xml->getAttributeValue(L"value");
					g->device->getFileSystem()->changeWorkingDirectoryTo(lastFolder.c_str());
					DEBUG_OUT("lastFolder %s\n", lastFolder.c_str());
				}

				if (!wcscmp(L"gridSize", xml->getNodeName()))
				{
					g->m_gridSize = xml->getAttributeValueAsInt(L"value");
					g->m_gridNode->SetSize(g->m_gridSize);
					DEBUG_OUT("m_gridSize %d\n", g->m_gridSize);
				}				

				if (!wcscmp(L"minId", xml->getNodeName()))
				{
					m_minId = xml->getAttributeValueAsInt(L"value");
					DEBUG_OUT("m_minId %d\n", m_minId);
				}

				if (!wcscmp(L"maxId", xml->getNodeName()))
				{
					m_maxId = xml->getAttributeValueAsInt(L"value");
					DEBUG_OUT("m_maxId %d\n", m_maxId);
				}

				if (!wcscmp(L"buildData", xml->getNodeName()))
				{
					core::stringc m_buildDataPath = xml->getAttributeValue(L"value");
					DEBUG_OUT("m_buildDataPath %s\n", m_buildDataPath.c_str());
				}

				if (!wcscmp(L"launchEmu", xml->getNodeName()))
				{
					core::stringc m_launchEmuPath = xml->getAttributeValue(L"value");
					DEBUG_OUT("m_launchEmuPath %s\n", m_launchEmuPath.c_str());
				}

				if (!wcscmp(L"mayacamerafar", xml->getNodeName()))
				{
					g->m_mayaCameraFar = xml->getAttributeValueAsFloat(L"value");
					DEBUG_OUT("m_mayaCameraFar %f\n", g->m_mayaCameraFar);

					if (g->camera[MAYA_CAMERA])
					{
						g->camera[MAYA_CAMERA]->setFarValue(g->m_mayaCameraFar);
					}
				} 
				else if (!wcscmp(L"mayacameraRotate", xml->getNodeName()))
				{
					g->m_mayaCameraRotate = xml->getAttributeValueAsFloat(L"value");
					DEBUG_OUT("mayacameraRotate %f\n", g->m_mayaCameraRotate);

					if (g->camera[MAYA_CAMERA])
					{
						list<ISceneNodeAnimator*> _animators = g->camera[MAYA_CAMERA]->getAnimators();
						list<ISceneNodeAnimator*>::Iterator it = _animators.begin();
												
						((CSceneNodeAnimatorCameraMaya*)(*it))->setRotateSpeed(g->m_mayaCameraRotate );
												
					}
				}
				else if (!wcscmp(L"mayacameraZoom", xml->getNodeName()))
				{
					g->m_mayaCameraZoom = xml->getAttributeValueAsFloat(L"value");
					DEBUG_OUT("mayacameraZoom %f\n", g->m_mayaCameraZoom);

					if (g->camera[MAYA_CAMERA])
					{
						list<ISceneNodeAnimator*> _animators = g->camera[MAYA_CAMERA]->getAnimators();
						list<ISceneNodeAnimator*>::Iterator it = _animators.begin();
												
						((CSceneNodeAnimatorCameraMaya*)(*it))->setZoomSpeed( g->m_mayaCameraZoom );
					}
				}
				else if (!wcscmp(L"mayacameraTranslate", xml->getNodeName()))
				{
					g->m_mayaCameraTranslate = xml->getAttributeValueAsFloat(L"value");
					DEBUG_OUT("mayacameraTranslate %f\n", g->m_mayaCameraTranslate);

					if (g->camera[MAYA_CAMERA])
					{
						list<ISceneNodeAnimator*> _animators = g->camera[MAYA_CAMERA]->getAnimators();
						list<ISceneNodeAnimator*>::Iterator it = _animators.begin();
						((CSceneNodeAnimatorCameraMaya*)(*it))->setMoveSpeed( g->m_mayaCameraTranslate );
					}
				}
				
			}
			break;
		}
	}

	xml->drop();

	return 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
int CLevelEditor::writeConfigOptions()
{
	core::stringc configPath = m_editorPath + "\\editor_config.xml";
	IXMLWriter* xml = g->device->getFileSystem()->createXMLWriter(configPath.c_str());

	if (!xml)
		return 1;
	
	xml->writeXMLHeader();

	core::stringw lastFolder = g->device->getFileSystem()->getWorkingDirectory();
	xml->writeElement(L"options", false);
	xml->writeLineBreak();
	xml->writeElement(L"lastFolder", true, L"value", lastFolder.c_str() );	
	xml->writeLineBreak();

	//ms fix
	stringw str = L"";
	str += g->m_gridNode->GetSize();

	xml->writeElement(L"gridSize", true, L"value",str.c_str());	
	xml->writeLineBreak();

	xml->writeElement(L"minId", true, L"value", stringw(m_minId).c_str());
	xml->writeLineBreak();
	xml->writeElement(L"maxId", true, L"value", stringw(m_maxId).c_str());
	xml->writeLineBreak();

	xml->writeElement(L"buildData", true, L"value", stringw(m_buildDataPath.c_str()).c_str() );	
	xml->writeLineBreak();

	xml->writeElement(L"launchEmu", true, L"value", stringw(m_launchEmuPath.c_str()).c_str() );	
	xml->writeLineBreak();

	str = L"";
	str += g->camera[MAYA_CAMERA]->getFarValue();

	xml->writeElement(L"mayacamerafar", true, L"value", str.c_str() );	
	xml->writeLineBreak();

	list<ISceneNodeAnimator*> _animators = g->camera[MAYA_CAMERA]->getAnimators();
	list<ISceneNodeAnimator*>::Iterator it = _animators.begin();
																	
	str = L"";
	str += ((CSceneNodeAnimatorCameraMaya*)(*it))->getRotateSpeed();

	xml->writeElement(L"mayacameraRotate", true, L"value", str.c_str() );	
	xml->writeLineBreak();

	str = L"";
	str += ((CSceneNodeAnimatorCameraMaya*)(*it))->getZoomSpeed();

	xml->writeElement(L"mayacameraZoom", true, L"value", str.c_str() );	
	xml->writeLineBreak();

	str = L"";
	str += ((CSceneNodeAnimatorCameraMaya*)(*it))->getMoveSpeed();

	xml->writeElement(L"mayacameraTranslate", true, L"value", str.c_str() );	
	xml->writeLineBreak();

	xml->writeClosingTag(L"options");
	xml->drop();

	return 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
int CLevelEditor::readGameObjects()
{
	u32 i;
	bool bUserData;
	bool bTypeLists;
	CGameObject* gameObject = 0;

	IXMLReader* xml = g->device->getFileSystem()->createXMLReader("game_objects.xml");
	IAttributes* attr = g->device->getFileSystem()->createEmptyAttributes();

	if (!xml)
		return 1;
	
	bUserData = false;
	bTypeLists = false;

	while (xml->read())
	{
		switch(xml->getNodeType())
		{
			case EXN_ELEMENT:
			{
				if (!wcscmp(L"typelists", xml->getNodeName()))
				{
					bTypeLists = true;
				}

				if (!wcscmp(L"object", xml->getNodeName()))
				{
					gameObject = new CGameObject();
					break;					
				}

				
				if (gameObject && !wcscmp(L"attributes", xml->getNodeName()))
				{
					gameObject->m_Attributes->read(xml, true);
				}
				
				if (bTypeLists && !wcscmp(L"attributes", xml->getNodeName()))
				{					
					SGameList list;
				
					attr->read(xml, true);

					for (i = 0; i < attr->getAttributeCount(); i ++)
					{
						list.Items.clear();	
						list.Name = attr->getAttributeName(i);
						if (list.Name == "File")
						{
							LoadListFromFile(attr->getAttributeAsString(i), list);
						}
						else
						{
							list.Items = attr->getAttributeAsArray(i);
						}

						m_GameLists.push_back(list);
					}
				}

			}
				break;

			case EXN_ELEMENT_END:
				if (!wcscmp(L"typelists", xml->getNodeName()))
					bTypeLists = false;

				if (!wcscmp(L"object", xml->getNodeName()))
				{					
					m_GameObjects.push_back(gameObject);

					//set cam ctrl point template
					stringc gameType = gameObject->m_Attributes->getAttributeAsString("!GameType");
					if (gameType == "CamCtrlPoint")
					{
						m_camCtrlPointTemplate = gameObject;
					}
					if (gameType == "RestorePoint")
					{
						m_restorePointTemplate = gameObject;
					}
					if (gameType == "Effect")
					{
						m_effectTemplate = gameObject;
					}
					gameObject = 0;
				}

				break;
		}
	}

	//unclosed object element
	//TODO: Show corrupted config file message
	if (gameObject)
	{
		xml->drop();		
		return 1;	
	}

	xml->drop();

	return 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
int CLevelEditor::readGameTemplates()
{
	bool bUserData;
	CGameObject* gameTemplate = 0;

	IXMLReader* xml = g->device->getFileSystem()->createXMLReader("game_templates.xml");
	IAttributes* attr = g->device->getFileSystem()->createEmptyAttributes();

	if (!xml)
		return 1;
	
	bUserData = false;

	while (xml->read())
	{
		switch(xml->getNodeType())
		{
			case EXN_ELEMENT:
			{
				if (!wcscmp(L"object", xml->getNodeName()))
				{
					gameTemplate = new CGameObject();
					break;					
				}

				
				if (gameTemplate && !wcscmp(L"attributes", xml->getNodeName()))
				{
					gameTemplate->m_Attributes->read(xml, true);
				}
			}
				break;

			case EXN_ELEMENT_END:

				if (!wcscmp(L"object", xml->getNodeName()))
				{
					stringc gameType = gameTemplate->m_Attributes->getAttributeAsString("!GameType");
					s32 index = getGameObjectIndexFromGameType(gameType);

					if (index != -1)
					{
						IAttributes *pAttr = m_GameObjects[index]->m_Attributes;

						//check for new attributes and copy them into template
						for (unsigned int i=0; i < pAttr->getAttributeCount(); i++)
						{
							if (gameTemplate->m_Attributes->findAttribute(pAttr->getAttributeName(i)) == -1)
							{
								switch (pAttr->getAttributeType(i))
								{
									case EAT_INT: 
										{
											gameTemplate->m_Attributes->addInt(pAttr->getAttributeName(i), 
													  pAttr->getAttributeAsInt(i));
										}
										break;

									case EAT_FLOAT: 
										{
											gameTemplate->m_Attributes->addFloat(pAttr->getAttributeName(i), 
												  pAttr->getAttributeAsFloat(i));
										}
										break;

									case EAT_STRING: 
										{
											gameTemplate->m_Attributes->addString(pAttr->getAttributeName(i), 
													 pAttr->getAttributeAsString(i).c_str());
										}
										break;

									case EAT_BOOL: 
										{
											gameTemplate->m_Attributes->addBool(pAttr->getAttributeName(i), 
												  pAttr->getAttributeAsBool(i));
										}
										break;

									case EAT_COLOR: 
										{
											gameTemplate->m_Attributes->addColor(pAttr->getAttributeName(i), 
												  pAttr->getAttributeAsColor(i));
										}
										break;

									case EAT_VECTOR3D: 
										{
											gameTemplate->m_Attributes->addVector3d(pAttr->getAttributeName(i), 
												  pAttr->getAttributeAsVector3d(i));
										}
										break;

									case EAT_QUATERNION:
										{
											gameTemplate->m_Attributes->addQuaternion(pAttr->getAttributeName(i), 
												  pAttr->getAttributeAsQuaternion(i));
										}
										break;

									default:
										assert(0);
										break;
								}
							}
						}

						//check for deleted attributes and delete them from template
						for (unsigned int i=0; i < gameTemplate->m_Attributes->getAttributeCount(); i++)
						{
							if (pAttr->findAttribute(gameTemplate->m_Attributes->getAttributeName(i)) == -1)
							{
								char* delAttr = NULL;
								gameTemplate->m_Attributes->setAttribute(gameTemplate->m_Attributes->getAttributeName(i), delAttr);
								i--;
							}
						}

						m_GameTemplates.push_back(gameTemplate);
					}

					gameTemplate = 0;
				}

				break;
		}
	}

	//unclosed object element
	//TODO: Show corrupted config file message
	if (gameTemplate)
	{
		xml->drop();		
		return 1;	
	}

	xml->drop();

	return 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool CLevelEditor::LoadListFromFile(stringc fileName, SGameList& list)
{
	IXMLReader* xml = g->device->getFileSystem()->createXMLReader(fileName.c_str());
	if (xml)
	{
		while (xml->read())
		{
			switch(xml->getNodeType())
			{
				case EXN_ELEMENT:
				{
					if (!wcscmp(L"attributes", xml->getNodeName()))
					{
						IAttributes* attr = g->device->getFileSystem()->createEmptyAttributes();
						attr->read(xml, true);

						for (u32 i = 0; i < attr->getAttributeCount(); i ++)
						{
							list.Name = attr->getAttributeName(i);
							list.Items = attr->getAttributeAsArray(i);
						}
					}
				}
			}
		}

		xml->drop();

		return true;
	}

	return false;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::AddCommand (IDoUndoCommand* command)
{
	if (m_LastCommand > 0)
	{
		if (m_clearHistoryOnNewCommand)
		{
			while (m_LastCommand > 0)
			{
				ui->m_HistoryList->removeItem(m_LastCommand - 1);
				m_HistoryCommands[m_LastCommand - 1]->drop();
				m_HistoryCommands.erase(m_LastCommand - 1);
				--m_LastCommand;
			}
		}
		else
		{
			ui->m_HistoryList->setItemOverrideColor(m_LastCommand, SColor(255, 0, 0, 0));
			CMultiCommand* undoCommands = new CMultiCommand;
			if (m_LastCommand == 1)
				undoCommands->setDescription(L"undo last command");
			else
				undoCommands->setDescription(stringw(L"undo last ") + stringw(m_LastCommand) + stringw(L" commands"));
			int start = m_LastCommand;
			while (m_LastCommand > 0)
			{
				IDoUndoCommand* reverse = m_HistoryCommands[start - m_LastCommand]->getReverse();
				undoCommands->addCommand(reverse);
				reverse->drop();
				--m_LastCommand;
			}
			ui->m_HistoryList->insertItem(0, undoCommands->getDescription().c_str(), -1);
			m_HistoryCommands.push_front(undoCommands);
		}
	}

	m_nHistoryCommands++;
	if(m_nHistoryCommands > NR_HISTORY_AUTOSAVE)
	{
		saveScene(true);
		m_nHistoryCommands = 0;
	}
	ui->m_HistoryList->insertItem(0, command->getDescription().c_str(), -1);
	m_HistoryCommands.push_front(command);
	m_LastCommand = 1;
	Redo();
	m_bModified = true;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::Redo ()
{
	if (m_LastCommand > 0)
	{
		m_HistoryCommands[m_LastCommand - 1]->redo();
		if (m_LastCommand < (int)m_HistoryCommands.size())
			ui->m_HistoryList->setItemOverrideColor(m_LastCommand, SColor(255, 0, 0, 0));
		ui->m_HistoryList->setItemOverrideColor(m_LastCommand - 1, SColor(255, 255, 0, 0));
		--m_LastCommand;
	}

	m_nHistoryCommands++;
	if(m_nHistoryCommands > NR_HISTORY_AUTOSAVE)
	{
		saveScene(true);
		m_nHistoryCommands = 0;
	}

	ui->updateProperties();
	updateControls();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::Undo ()
{
	if (m_LastCommand < (int)m_HistoryCommands.size() - 1)
	{
		m_HistoryCommands[m_LastCommand]->undo();
		ui->m_HistoryList->setItemOverrideColor(m_LastCommand, SColor(255, 0, 0, 0));
		ui->m_HistoryList->setItemOverrideColor(m_LastCommand + 1, SColor(255, 255, 0, 0));
		++m_LastCommand;
	}

	m_nHistoryCommands++;
	if(m_nHistoryCommands > NR_HISTORY_AUTOSAVE)
	{
		saveScene(true);
		m_nHistoryCommands = 0;
	}

	ui->updateProperties();
	updateControls();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
int CLevelEditor::init()
{
	m_mouseClicked = false;

	for (int i = 0; i < KEY_KEY_CODES_COUNT; ++i)
		m_KeysDown[i] = false;

	//CCommonGLMaterialRenderer* mat0 = new CCommonGLMaterialRenderer_ALPHA_TEST_NONTRANSPARENT((irr::video::CCommonGLDriver *)g->device->getVideoDriver());
	//CCommonGLMaterialRenderer* mat1 = new CCommonGLMaterialRenderer_ADDITIVE_REPLACE_NONTRANSPARENT((irr::video::CCommonGLDriver *)g->device->getVideoDriver());
	//CCommonGLMaterialRenderer* mat2 = new CCommonGLMaterialRenderer_ADDITIVE_MODULATE_NONTRANSPARENT((irr::video::CCommonGLDriver *)g->device->getVideoDriver());
	//CCommonGLMaterialRenderer* mat3 = new CCommonGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_WITH_VERTEX_ALPHA((irr::video::CCommonGLDriver *)g->device->getVideoDriver());
	//CCommonGLMaterialRenderer* mat4 = new CCommonGLMaterialRenderer_LIGHTMAP_LIGHTING_ADD((irr::video::CCommonGLDriver *)g->device->getVideoDriver());

	//g->device->getVideoDriver()->addMaterialRenderer(mat0, "nontransparent_alpha_test");
	//g->device->getVideoDriver()->addMaterialRenderer(mat1, "nontransparent_additive_replace");
	//g->device->getVideoDriver()->addMaterialRenderer(mat2, "nontransparent_additive_modulate");
	//g->device->getVideoDriver()->addMaterialRenderer(mat3, "transparent_alpha_channel_with_vertex_alpha");
	//g->device->getVideoDriver()->addMaterialRenderer(mat4, "lightmap_additive");
	//g->device->getVideoDriver()->addMaterialRenderer(mat4, "lightmap_substract");

	//mat0->drop();
	//mat1->drop();
	//mat2->drop();
	//mat3->drop();
	//mat4->drop();

	int result = readGameObjects();

	if (!result)
		ui->populateGameObjectList();

	ui->populateTemplatesCombo();

	readGameTemplates();

	ui->populateTemplatesList();

	CSpriteManager::newInstance();

	//readEffectsPreset();

	AddEffectToTypeList();

	ui->populateEffectsList();

	readConfigOptions();
	m_nHistoryCommands = 0;
	m_LastCommand = 0;
	AddCommand(new CEmptyCommand);

	m_lastUniqueId = 0;

	m_clearHistoryOnNewCommand = true;

	m_mouseDraggedWithCtrl = false;

	m_updateControls = false;

	return result;	
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool CLevelEditor::isPointOverGUIElement(position2di pos, IGUIElement* e) 
{
  if (e->getElementFromPoint(pos) != NULL) return true;
  
  list<IGUIElement*> children = e->getChildren();
  list<IGUIElement*>::Iterator iter = children.begin();
  while (iter != children.end()) {
    if (e->getElementFromPoint(pos)) return true;
    iter++;      
  }
  
  return false;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool CLevelEditor::isPointOverGUI(core::position2di pos) 
{
   IGUIElement* root = g->device->getGUIEnvironment()->getRootGUIElement();

   list<IGUIElement*> children = root->getChildren();
   list<IGUIElement*>::Iterator iter = children.begin();
   while (iter != children.end()) 
   {
     if (isPointOverGUIElement(pos, *iter)) 
		 return true;
     iter++;      
   }
   
   return false;
       
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool SameRotation (quaternion a, quaternion b)
{
	return a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.W == b.W;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
extern CLevelEditor* editor;

void focusCameraOn (ISceneNode* node)
{
	ICameraSceneNode* cam = g->sceneManager->getActiveCamera();
	matrix4 m = cam->getAbsoluteTransformation();
	vector3df target = cam->getTarget();
	//m.transformVect(target);
	vector3df pos = cam->getPosition();
	//vector3df moveBy = getNodeCenter(node) - target;
	vector3df moveBy = node->getAbsolutePosition() - target;

	CSceneObject* obj = editor->getSceneObjectFromID(node->getID());
	if (obj && obj->m_UserData->getAttributeAsString("!GameType") == "Geometry")
	{
		ISceneNode* rNode = editor->GetRoomRefNode( node );

		if (rNode)
		{
			 moveBy = rNode->getAbsolutePosition() - target;
		}
	}
	cam->setTarget(target + moveBy);
	cam->setPosition(pos + moveBy);
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool CLevelEditor::receiveEvent(const SEvent& event)
{	
	if(editor && editor->m_isPlayingCinematic)
	{
		if(event.EventType == EET_KEY_INPUT_EVENT)
		{
			if(event.KeyInput.Key == KEY_ESCAPE)
				editor->OnOffPlayCinematic(false);
			else if(event.KeyInput.Key == KEY_PAUSE && !event.KeyInput.PressedDown)
				editor->PausePlayCinematic();
			else if(event.KeyInput.Key == KEY_SPACE && event.KeyInput.PressedDown)
				editor->StepPlayCinematic();			
		}
		return true;
	}

	if (event.EventType == irr::EET_KEY_INPUT_EVENT && ui->m_CinematicEditor.m_Active
		&& event.KeyInput.Key != KEY_RETURN
		&& event.KeyInput.Key != KEY_ESCAPE
		&& event.KeyInput.Key != KEY_BACK)
	{
		return false;
	}

	if(editor && editor->m_isMovingObject)
	{
		if(event.EventType == EET_KEY_INPUT_EVENT &&
			event.KeyInput.Key == KEY_ESCAPE)
		{
			editor->MoveObject(false);
		}
	}

	if( g->getActiveCameraIndex() == CONTROL_POINT_CAMERA )
	{
		if(event.EventType == EET_KEY_INPUT_EVENT)
		{
			if(event.KeyInput.Key == KEY_RETURN)
			{//commit edit
				editor->OnOffCameraModeCtrlPoint(false);
				ui->m_SetCameraButton->setPressed(false);
				return true;
			}
			else if(event.KeyInput.Key == KEY_ESCAPE)
			{//cancel edit
				editor->OnOffCameraModeCtrlPoint(false,true);
				ui->m_SetCameraButton->setPressed(false);
				return true;
			}
			else if(event.KeyInput.Key == KEY_BACK)
			{//restore camera value not exit edit mode
				CCtrolPointCameraAnimator* anim = (CCtrolPointCameraAnimator*)*g->camera[CONTROL_POINT_CAMERA]->getAnimators().begin();
				anim->resetCurrentControlPointCamera();
				return true;
			}			
		}
		return false;
	}

	if( g->getActiveCameraIndex() == CHANGE_CAMERA)
	{		
		if(event.EventType == EET_KEY_INPUT_EVENT)
		{
			if(event.KeyInput.Key == KEY_RETURN)
			{//commit edit
				editor->ChangeCamera(false);				
				return true;
			}
			else if(event.KeyInput.Key == KEY_ESCAPE)
			{//cancel edit
				editor->ChangeCamera(false,true);						
				return true;
			}
			else if(event.KeyInput.Key == KEY_BACK)
			{//restore camera value not exit edit mode
				CChangeCameraAnimator* anim = (CChangeCameraAnimator*)*g->camera[CHANGE_CAMERA]->getAnimators().begin();				
				anim->resetCamera();
				return true;
			}			
		}
		return false;
	}
	

	if (g->getActiveCameraIndex() == FPS_CAMERA &&
		event.EventType == EET_KEY_INPUT_EVENT &&
		event.KeyInput.Key == KEY_SHIFT)
	{
		list<ISceneNodeAnimator*> _animators = g->camera[FPS_CAMERA]->getAnimators();
		list<ISceneNodeAnimator*>::Iterator it = _animators.begin();
		
		if (event.KeyInput.PressedDown)
		{
			((scene::ISceneNodeAnimatorCameraFPS*)(*it))->setMoveSpeed(100.0f / 1000.0f);
		}
		else
		{
			((scene::ISceneNodeAnimatorCameraFPS*)(*it))->setMoveSpeed(500.0f / 1000.0f);
		}
	}

	if (g->getActiveCameraIndex() != MAYA_CAMERA && 		
		event.EventType == EET_KEY_INPUT_EVENT &&
		event.KeyInput.Key == KEY_ESCAPE)
	{		
		g->setActiveCamera(MAYA_CAMERA);		
	}

	if (event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.Key == KEY_KEY_G && !event.KeyInput.PressedDown)
	{
		g->switchGrid();
	} 
	else if (event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.Key == KEY_CONTROL)
	{
		m_LastFocusedNode = 0;
		if (!event.KeyInput.PressedDown)
			m_mouseDraggedWithCtrl = false;
	}

	if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.Key == KEY_PLUS && !event.KeyInput.PressedDown && !g->eventReceiver->IsKeyDown(KEY_CONTROL))
	{
		switchSelAllCameras();
		return true;
	}

	if (event.EventType == EET_MOUSE_INPUT_EVENT
		&& g->eventReceiver->IsKeyDown(KEY_CONTROL)
		&& !isPointOverGUI(g->device->getCursorControl()->getPosition()))
	{
		switch (event.MouseInput.Event)
		{
		case EMIE_LMOUSE_PRESSED_DOWN:
			m_mouseDraggedWithCtrl = true;
			m_mouseDragStart = position2di(event.MouseInput.X, event.MouseInput.Y);
			return true;

		case EMIE_LMOUSE_LEFT_UP:
			m_mouseDraggedWithCtrl = false;
			if (abs(event.MouseInput.X - m_mouseDragStart.X) <= 1 &&
				abs(event.MouseInput.Y - m_mouseDragStart.Y) <= 1 &&
				m_selectedIndices.size() > 1)
			{
				// open a context menu so that a new item can be selected
				IGUIContextMenu* menu = g->guienv->addContextMenu(rect<s32>(m_mouseDragStart - position2di(2,2), dimension2di(10,10)));
				m_menuIds.clear();
				for (int i = 0; i < (int)m_selectedIndices.size(); ++i)
				{
					int idx = m_selectedIndices[i];
					int id = m_onScreenIds[idx];
					CSceneObject* obj = getSceneObjectFromID(id);
					stringw name = obj->m_UserData->getAttributeAsStringW("Name") +
						L"(" + stringw(obj->m_SceneNode->getID()) + L")";
					menu->addItem(name.c_str(), CONTEXTMENU_ID_SELECT);
					m_menuIds.push_back(id);
				}
			}
			else
			{
				for (int i = 0; i < (int)m_selectedIndices.size(); ++i)
				{
					int id = m_onScreenIds[m_selectedIndices[i]];
					toggleToSelection(getSceneObjectFromID(id)->m_SceneNode);
				}
			}
			return true;

		case EMIE_MOUSE_MOVED:
			return m_mouseDraggedWithCtrl;
		}
	}

	if (g->eventReceiver->IsKeyDown(KEY_CONTROL))
	{
		//undo
		if (event.KeyInput.Key == KEY_KEY_Z && !event.KeyInput.PressedDown)
		{
			Undo();
		}
		if (event.KeyInput.Key == KEY_KEY_Y && !event.KeyInput.PressedDown)
		{
			Redo();
		}

		// save
		if (event.KeyInput.Key == KEY_KEY_S && !event.KeyInput.PressedDown)
		{
			CEmptyCommand *save = new CEmptyCommand();

			save->setDescription("save");
			editor->AddCommand(save);
			ui->trySave();
		}

		// select cameras
		if (event.KeyInput.Key == KEY_KEY_1 && !event.KeyInput.PressedDown)
		{
			g->setActiveCamera(MAYA_CAMERA);
		}
		if (event.KeyInput.Key == KEY_KEY_2 && !event.KeyInput.PressedDown)
		{
			g->setActiveCamera(CAMERA_XY);
		}
		if (event.KeyInput.Key == KEY_KEY_3 && !event.KeyInput.PressedDown)
		{
			g->setActiveCamera(FPS_CAMERA);
		}
		return false;
	}

	if (event.EventType == EET_KEY_INPUT_EVENT && m_SelectedNode)
	{
		//removed: don't know the usage and may cause bug

		/*if (event.KeyInput.Key == KEY_EDIT_X || 
			event.KeyInput.Key == KEY_EDIT_Y ||
			event.KeyInput.Key == KEY_EDIT_Z ||
			event.KeyInput.Key == KEY_EDIT_ALL)
		{
			if (event.KeyInput.PressedDown)
			{
				if (!m_KeysDown[event.KeyInput.Key])
				{
					m_SelectedNodePos = m_SelectedNode->getPosition();
					m_SelectedNodeRot = m_SelectedNode->getRotation();
					m_SelectedNodeScale = m_SelectedNode->getScale();

					m_SelectedMousePos = g->device->getCursorControl()->getPosition();				
					g->sceneManager->getActiveCamera()->setInputReceiverEnabled(false);

					m_KeysDown[event.KeyInput.Key] = true;
				}
			}
			else
			{
				vector3df pos = m_SelectedNode->getPosition();
				quaternion rot = m_SelectedNode->getRotation();
				vector3df scale = m_SelectedNode->getScale();
				if (m_SelectedNodePos != pos)
					AddCommand(new CMoveCommand(m_SelectedNode->getID(), m_SelectedNodePos, pos));
				if (!SameRotation(m_SelectedNodeRot, rot))
					AddCommand(new CRotateCommand(m_SelectedNode->getID(), m_SelectedNodeRot, rot));
				if (m_SelectedNodeScale != scale)
					AddCommand(new CScaleCommand(m_SelectedNode->getID(), m_SelectedNodeScale, scale));

				g->sceneManager->getActiveCamera()->setInputReceiverEnabled(true);

				m_KeysDown[event.KeyInput.Key] = false;
			}
		}*/
		if (event.KeyInput.Key == KEY_BUTTON_MOVE||
			event.KeyInput.Key == KEY_BUTTON_ROTATE||
			event.KeyInput.Key == KEY_BUTTON_SCALE||
			event.KeyInput.Key == KEY_BUTTON_UNSELECT)
		{
			ui->m_MovePushButton->setPressed(event.KeyInput.Key == KEY_BUTTON_MOVE);
			ui->m_MoveLocalPushButton->setPressed(false);
			ui->m_RotatePushButton->setPressed(event.KeyInput.Key == KEY_BUTTON_ROTATE);
			ui->m_RotateLocalPushButton->setPressed(false);
			ui->m_ScalePushButton->setPressed(event.KeyInput.Key == KEY_BUTTON_SCALE);
			ui->m_ModifyPushButton->setPressed(false);
			if(event.KeyInput.Key == KEY_BUTTON_UNSELECT)
			{
					if(ui->m_sceneGraphTree)
						ui->m_sceneGraphTree->SetSelected(0);
					((CListBox*)ui->m_SceneGraphPropertiesVisibleList)->setSelected(-1);
					((CListBox*)ui->m_SceneGraphPropertiesInvisibleList)->setSelected(-1);
					((CListBox*)ui->m_SceneGraphPropertiesLockedList)->setSelected(-1);

			}
			updateControls();
		}
		
		if (event.KeyInput.Key == KEY_DELETE && m_SelectedNode && 
			!event.KeyInput.PressedDown)
		{
			IGUIElement* focus = g->guienv->getFocus();
			if (!focus)
			{
				checkReferentialIntegrity();
				return true;
			}
			return false;
		}

	}

	if (event.EventType == EET_MOUSE_INPUT_EVENT)
	{
		position2di mousePos = g->device->getCursorControl()->getPosition();
		
		ISceneCollisionManager* colmgr = g->sceneManager->getSceneCollisionManager();		

		line3df ray = colmgr->getRayFromScreenCoordinates(mousePos, g->sceneManager->getActiveCamera());

		if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
		{
			if (isPointOverGUI(mousePos)) 
				return false;

			m_mouseClicked = true;
			m_mouseClickPos = mousePos;

			return false;
		}

		if (event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)
		{
			m_bPositionObjOnInsert = false;
			m_LastCreatedObjID = -1;

			//m_bLinkRoomMode = false;
		}

		if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
		{
			if (isPointOverGUI(mousePos)) 
				return false;

			if (m_mouseClicked)
			{
				position2di diff = m_mouseClickPos - mousePos;
				if (abs(diff.X) <= 1 && abs(diff.Y) <= 1)
				{
					//link room mode
					if (m_bLinkRoomMode)
					{
						ISceneNode* focused_node;
						//if(g->eventReceiver->IsKeyDown(KEY_SHIFT))//dai_yx
						//	focused_node = colmgr->getSceneNodeFromRayBBWithFilter(ray,false,"Geometry");
						//else
							focused_node = colmgr->getSceneNodeFromRayBB(ray);

						if (focused_node)
						{
							bool bFound = false;
							int index;

							ISceneNode *pParent = focused_node->getParent();

							if (pParent)
							{
								for (int i=0; i < MAX_ROOM_LINKS; i++)
								{
									stringc name("LinkNode");
									name += i;

									if (name == pParent->getName())
									{
										bFound = true;
										index = i;
										break;
									}
								}
							}

							if (bFound)
							{
								if (m_bLinkRoomModeStep == 0)
								{
									m_pLinkFrom = focused_node;
									ShowRoomHelpers(GetRoomFromHelper(m_pLinkFrom), false);
									setSelectedNode(0);
									m_bLinkRoomModeStep++;
									m_linkFromIndex = index;
								}
								else
								{
									m_pLinkTo = focused_node;
									m_linkToIndex = index;
									ShowRoomHelpers(GetRoomFromHelper(m_pLinkFrom), true);

									CMultiCommand* command = new CMultiCommand;

									LinkRoomFromTo(m_pLinkFrom->getParent(), m_linkFromIndex, m_pLinkTo->getParent(), m_linkToIndex, command);

									CSceneObject *pObj = getSceneObjectFromID(GetRoomFromHelper(m_pLinkFrom)->getID());
									CSceneObject *pObj1 = getSceneObjectFromID(GetRoomFromHelper(m_pLinkTo)->getID());

									command->setDescription(stringw(L"Link room '") + pObj->m_UserData->getAttributeAsStringW("Name") + L"' to room '" + pObj1->m_UserData->getAttributeAsStringW("Name") + L"'");
									AddCommand(command);

									m_bLinkRoomMode = false;
								}
							}
						}
					}
					else
					if (m_bPositionObjOnInsert)
					{
						s32 oldLastObjID = m_LastCreatedObjID;
						CSceneObject* oldLastObj = getSceneObjectFromID(oldLastObjID);

						CSceneObject* pLastCreatedObj = createGameObject(m_pInsertObjTemplate, -1, true);
						if (pLastCreatedObj == NULL)
							return false;
						pLastCreatedObj->InitAttributes();

						m_LastCreatedObjID = pLastCreatedObj->m_SceneNode->getID();

						if (pLastCreatedObj && pLastCreatedObj->m_UserData->getAttributeAsString("!GameType") == "WayPoint" &&
							oldLastObj && oldLastObj->m_UserData->getAttributeAsString("!GameType") == "WayPoint")
						{
							oldLastObj->m_UserData->setAttribute("^Next1^WayPoint", m_LastCreatedObjID);
						}

						setSelectedNode(pLastCreatedObj->m_SceneNode);

						//AddInsertCommand(pLastCreatedObj);
					}
					else
					//link mode
					if (ui->m_linkChangedProp != NULL)
					{
						if (m_LastFocusedNode)
						{
							stringw filter = GetFilterFromName(ui->m_linkChangedProp->m_Name);

							ISceneNode* focused_node = NULL;//colmgr->getSceneNodeFromRayBBWithFilter(ray, true, stringc(filter.c_str()).c_str());//dai_yx

							if (m_LastFocusedNode == focused_node)
							{
								while (m_LastFocusedNode->getID() < 0 && m_LastFocusedNode->getParent() != NULL)
								{
									m_LastFocusedNode = m_LastFocusedNode->getParent();
								}

								if (filter == "" || getSceneObjectFromID(m_LastFocusedNode->getID())->m_UserData->getAttributeAsStringW("!GameType") == filter)
								{
									AddCommand(new CSetIntAttributeCommand(m_SelectedNode->getID(),
										stringc(ui->m_linkChangedProp->m_Name.c_str()), m_LastFocusedNode->getID()));

									((IGUIButton*)ui->m_linkChangedProp->m_GUIElementButton)->setPressed(false);
									ui->m_linkChangedProp = NULL;
									m_LastFocusedNode = NULL;
								
									//ui->m_SceneGraphWindow->setVisible(true);
									//ui->m_ToolsWindow->setVisible(true);
								}
							}
							else
							{
								m_LastFocusedNode = focused_node;
							}
						}
						else
						{
							FocusNodeForSelection(ray, mousePos);
						}
					}
					else
					{
						//grab selected node if any
						if (m_LastFocusedNode)
						{
							ISceneNode* focused_node;
							//if(g->eventReceiver->IsKeyDown(KEY_SHIFT))
							//	focused_node = colmgr->getSceneNodeFromRayBBWithFilter(ray,false,"Geometry");
							//else
								focused_node = colmgr->getSceneNodeFromRayBB(ray);

							if (m_LastFocusedNode == focused_node)
							{
								while (m_LastFocusedNode->getID() < 0 && m_LastFocusedNode->getParent() != NULL)
								{
									m_LastFocusedNode = m_LastFocusedNode->getParent();
								}


								if (m_LastFocusedNode && m_LastFocusedNode->getID() >= 0) 
								{
									setSelectedNode(m_LastFocusedNode);
								}
								m_LastFocusedNode = 0;
							}
							else
							{
								m_LastFocusedNode = focused_node;
							}
						}
						else
						{
							setSelectedNode(0);
							
							FocusNodeForSelection(ray, mousePos);
						}
					}
				}
				m_mouseClicked = false;
			}

			return false;
		}		

		if (event.MouseInput.Event == EMIE_MOUSE_MOVED)
		{

		}	
		
		//if (event.MouseInput.Event == EMIE_MOUSE_WHEEL && g->getActiveCameraIndex() == MAYA_CAMERA)
		//{
		//	if (isPointOverGUI(mousePos)) 
		//	{
		//		return false;
		//	}
		//	
		//	vector3df tPos = g->sceneManager->getActiveCamera()->getTarget();
		//	vector3df cPos = g->sceneManager->getActiveCamera()->getPosition();
		//	//vector3df moveBy = ( (tPos - cPos) ) / (tPos - cPos).getLength();
		//	vector3df moveBy =  15.0f * (tPos - cPos) * (s32)event.MouseInput.Wheel / (tPos - cPos).getLength();
		//	g->sceneManager->getActiveCamera()->setPosition(cPos + moveBy);
		//	g->sceneManager->getActiveCamera()->setTarget(tPos + moveBy);
		//	//vector3df cam = cPos + moveBy;
		//	//vector3df target = tPos + moveBy;
		//	//printf( "\n---------------------\n camera (%f %f %f ) ,\n target ( %f , %f , %f ) , \n moveBy ( %f , %f ,%f)" , cam.X , cam.Y , cam.Z , target.X , target.Y , target.Z  , moveBy.X , moveBy.Y , moveBy.Z);
		//	//ms fix ??  input should be absorbed 	

		//	return true;
		//}

	}
	
	return false;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::FocusNodeForSelection(line3df ray, position2di mousePos)
{
	ISceneCollisionManager* colmgr = g->sceneManager->getSceneCollisionManager();		

	if (m_SelectedNode)
	{
		if (ui->m_linkChangedProp != NULL)
		{
			stringw filter = GetFilterFromName(ui->m_linkChangedProp->m_Name);
			ISceneNode* focused_node = colmgr->getSceneNodeFromRayBB(ray);
			ISceneNode* pNode = focused_node;
			while (pNode && pNode->getID() < 0 && pNode->getParent() != NULL)
			{
				pNode = pNode->getParent();
			}

			if (pNode && pNode != g->sceneManager->getRootSceneNode())
			{					
				m_LastFocusedNode = focused_node;
			}
		}

		if (g->eventReceiver->IsKeyDown(KEY_EDIT_X))
			editObject(true, false, false, mousePos);

		if (g->eventReceiver->IsKeyDown(KEY_EDIT_Y))
			editObject(false, true, false, mousePos);

		if (g->eventReceiver->IsKeyDown(KEY_EDIT_Z))
			editObject(false, false, true, mousePos);

		if (g->eventReceiver->IsKeyDown(KEY_EDIT_ALL))
			editObject(true, true, true, mousePos);
	}
	else
	{
		//light up focused node
		ISceneNode* focused_node;
		if(g->eventReceiver->IsKeyDown(KEY_SHIFT))
			focused_node = colmgr->getSceneNodeFromRayBB(ray,false,"Geometry");
		else
			focused_node = colmgr->getSceneNodeFromRayBB(ray);
		
		if (focused_node /*&& focused_node->getID() >= 0*/ && !g->eventReceiver->IsKeyDown(KEY_CONTROL))
		{
			ISceneNode* pNode = focused_node;
			while (pNode->getID() < 0 && pNode->getParent() != NULL)
			{
				pNode = pNode->getParent();
			}

			if (pNode && pNode != g->sceneManager->getRootSceneNode())
			{					
					m_LastFocusedNode = focused_node;

			}
		}
		else
		{
			m_LastFocusedNode = 0;
			if (m_SelectedNode)
				setSelectedNode(0);
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
int CLevelEditor::getUniqueSceneObjectID( int oldId )
{
	if (oldId == -1) 
	{
		if (m_lastUniqueId < m_minId)
		{
			m_lastUniqueId = m_minId;
		}

		if (m_lastUniqueId >= m_maxId - 2)
		{
			g->guienv->addMessageBox(L"Error!", L"Message ID reached limit!!! \nChange the range of ids in 'editor_config.xml' to be able to add objects!!!", true);
		}

		return m_lastUniqueId++;
	}
	
	if (oldId >= m_minId && oldId < m_maxId)
	{
		m_lastUniqueId = MAX(m_lastUniqueId, oldId + 1);
	}

	return oldId;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::drawFocusBoundingBox()
{
	ISceneNode* nodeToBound;
	SColor boundColor;

	if (m_LastFocusedNode)
	{
		nodeToBound = m_LastFocusedNode;
		boundColor = SColor(200, 0, 128, 255);
	}
	else 
		if (m_SelectedNode)
		{
			if (m_selection.size() > 1)
				return;
			nodeToBound = m_SelectedNode;
			boundColor = SColor(200, 0, 128, 255);
		}
		else
			return;
   
   SMaterial matl;
   matl.setFlag(EMF_LIGHTING, false);
   g->driver->setMaterial(matl);

	//irr::scene::CColladaMesh* pMesh = NULL;
	//if (nodeToBound->getType() == ESNT_COLLADA_MESH ||
	//	nodeToBound->getType() == ESNT_COLLADA_SKIN_MESH ||
	//	nodeToBound->getType() == ESNT_COLLADA_MODULAR_SKIN_MESH)
	//{
	//	pMesh = (irr::scene::CColladaMesh*)((CColladaMeshSceneNode*)nodeToBound)->getMesh();
	//}

	g->driver->setTransform(ETS_WORLD, core::IdentityMatrix);

	//if (!pMesh || (pMesh->getType() != irr::scene::IColladaMesh::ET_SKINNED_MESH &&
	//				pMesh->getType() != irr::scene::IColladaMesh::ET_MODULAR_SKINNED_MESH))
	//{
	//	//g->driver->setTransform(ETS_WORLD, nodeToBound->getAbsoluteTransformation());
	//}

    //g->driver->applyMatricesChanges(false);
    //g->driver->draw3DBox(nodeToBound->getBoundingBox(), boundColor);
	g->driver->draw3DBox(nodeToBound->getTransformedBoundingBox(), boundColor);

   //if (m_HasActiveZone)
   //{
	  // aabbox3df activeZoneBox;
	  // activeZoneBox.MinEdge = vector3df();
	  // activeZoneBox.MaxEdge = vector3df(1.0f, 1.0f, 1.0f);
	  // activeZoneBox.MaxEdge *= m_SelevtedNodeActiveZoneScale;
	  // activeZoneBox.MinEdge += m_SelectedNodeActiveZonePos;
	  // activeZoneBox.MaxEdge += m_SelectedNodeActiveZonePos;
	  // g->driver->draw3DBox(activeZoneBox, SColor(255, 255, 255, 0));
   //}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::drawWaypointConnections()
{
	SMaterial matl;
	matl.setFlag(EMF_LIGHTING, false);
	g->driver->setMaterial(matl);
	matrix4 mat;

    g->driver->setTransform(ETS_WORLD, mat);
	
	//g->driver->draw3DLine(m_screenRay.start, m_screenRay.end);
	//g->driver->draw3DTriangle(m_collTriangle);

	SMeshBuffer Buffer;
	Buffer.Indices.clear();
	Buffer.Vertices.clear();

	Buffer.Material.setFlag(EMF_WIREFRAME, false);
	Buffer.Material.setFlag(EMF_LIGHTING, false);
	Buffer.Material.Thickness = 1;
	Buffer.Material.setFlag(EMF_FOG_ENABLE, false);
	
	video::S3DVertex m_vertexBuffer[3];// = new video::S3DVertex[3];
	u16 m_indexBuffer[3] ;//= new u16[3];

	for (u32 i = 0; i < m_SceneObjects.size(); i ++)
	{
		if (m_SceneObjects[i]->m_type == E_OBJ_WAYPOINT)
		{
			int nextID = m_SceneObjects[i]->m_UserData->getAttributeAsInt("^Next1^WayPoint");
			drawConnection(m_SceneObjects[i]->m_SceneNode, nextID, Buffer , m_indexBuffer , m_vertexBuffer);
			nextID = m_SceneObjects[i]->m_UserData->getAttributeAsInt("^Next2^WayPoint");
			drawConnection(m_SceneObjects[i]->m_SceneNode, nextID, Buffer , m_indexBuffer , m_vertexBuffer);
		}
		else if (m_SceneObjects[i]->m_type == E_OBJ_GRID_WAYPOINT)
		{
			int leftID = m_SceneObjects[i]->m_UserData->getAttributeAsInt("^Left^GridWayPoint");
			int rightID = m_SceneObjects[i]->m_UserData->getAttributeAsInt("^Right^GridWayPoint");
			int upID = m_SceneObjects[i]->m_UserData->getAttributeAsInt("^Up^GridWayPoint");
			int downID = m_SceneObjects[i]->m_UserData->getAttributeAsInt("^Down^GridWayPoint");
			
			drawConnection(m_SceneObjects[i]->m_SceneNode, leftID, Buffer , m_indexBuffer , m_vertexBuffer);
			drawConnection(m_SceneObjects[i]->m_SceneNode, rightID, Buffer , m_indexBuffer , m_vertexBuffer );
			drawConnection(m_SceneObjects[i]->m_SceneNode, upID, Buffer , m_indexBuffer , m_vertexBuffer);
			drawConnection(m_SceneObjects[i]->m_SceneNode, downID, Buffer , m_indexBuffer , m_vertexBuffer);
		}
	}

	//g->driver->drawVertexPrimitiveList(Buffer.getVertices(), //by dai_yx
	//	Buffer.getIndices(), 
	//	0,
	//	Buffer.getIndexCount(),
	//	Buffer.getVertexCount()/3, 
	//	video::EVT_STANDARD, 
	//	scene::EPT_TRIANGLES, 
	//	video::EIT_16BIT);
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline std::vector<CSceneObject*> getCameraAreaControlPoints(CLevelEditor& editor, CSceneObject* obj)
{
	std::vector<CSceneObject*> ccps;
	ccps.reserve(4);
	char tmp_buf[512];
	for(int i=0; i<4; i++)
	{
		sprintf_s(tmp_buf,"^Point%d^CamCtrlPoint",(i+1));
		int ccpID = obj->m_UserData->getAttributeAsInt(tmp_buf);
		if(ccpID>=0)
		{
			CSceneObject* ccp= editor.getSceneObjectFromID(ccpID);
			if(ccp!=0)
				ccps.push_back(ccp);
		}
	}	
	return ccps;
}

bool CLevelEditor::isCameraAreaSelected(CSceneObject* obj)
{
	std::vector<CSceneObject*> &ccps = getCameraAreaControlPoints(*this, obj);

	for (unsigned int i = 0; i < m_selection.size(); ++i)
	{
		if(m_selection[i] == obj)
			return true;
		else
		{
			for(unsigned int j=0; j<ccps.size(); ++j)
			{
				if(m_selection[i]==ccps[j])
					return true;
			}
		}
	}

	return false;
}

void CLevelEditor::drawCCPDirectionLine(CSceneObject* obj)
{
	irr::core::vector3df dir;
	float dx = obj->m_UserData->getAttributeAsFloat("dx");
	float dy = obj->m_UserData->getAttributeAsFloat("dy");
	float dz = obj->m_UserData->getAttributeAsFloat("dz");	
	dir.set(dx,dy,dz);
	dir.normalize();
	dir*=100;

	irr::core::vector3df start = obj->m_SceneNode->getAbsolutePosition();
	irr::core::vector3df end = start + dir;

	SColor color_wp(255, 255, 0, 255);					
	g->driver->draw3DLine(start, end, color_wp);
}

void CLevelEditor::drawCCPTargetOffset(CSceneObject* obj)
{
	irr::core::vector3df tarOff;
	float dx = obj->m_UserData->getAttributeAsFloat("targetOffsetX");
	float dy = obj->m_UserData->getAttributeAsFloat("targetOffsetY");
	float dz = obj->m_UserData->getAttributeAsFloat("targetOffsetZ");	
	tarOff.set(dx,dy,dz);	

	irr::core::vector3df start = obj->m_SceneNode->getAbsolutePosition();
	irr::core::vector3df end = start + tarOff;

	SColor color_wp(255, 0, 0, 255);					
	g->driver->draw3DLine(start, end, color_wp);
}

void CLevelEditor::drawCameraAreaNormalRange(CSceneObject* obj, bool isSelected)
{	
	irr::core::vector3df normal = obj->m_UserData->getAttributeAsVector3d("normal");
	if(obj->m_UserData->getAttributeAsBool("inverseNormal"))
	{
		normal*=-1;
	}

	normal*= obj->m_UserData->getAttributeAsFloat("height");	

	irr::core::vector3df start = obj->m_SceneNode->getAbsolutePosition();
	irr::core::vector3df end = start + normal;

	SColor color_wp(255, 255, 255, 0);					
	g->driver->draw3DLine(start, end, color_wp);

	if(isSelected)
	{
		//draw area space
		std::vector<CSceneObject*> &ccps = getCameraAreaControlPoints(*this, obj);
		if(ccps.size()!=4)
			return;
		for(int i=0; i<4; i++)
		{
			irr::core::vector3df start = ccps[i]->m_SceneNode->getAbsolutePosition();
			irr::core::vector3df end = start + normal;
			g->driver->draw3DLine(start, end, color_wp);

			int next_idx = i+1;
			if(next_idx==4)
				next_idx=0;
			irr::core::vector3df next = ccps[next_idx]->m_SceneNode->getAbsolutePosition()+normal;
			g->driver->draw3DLine(end, next, color_wp);

		}

		//draw target area link lines
		char tmp_buf[512];
		for(int i=0; i<4; i++)
		{
			int next_idx = i+1;
			if(next_idx==4)
				next_idx=0;

			sprintf_s(tmp_buf,"^Point%d^CamCtrlPoint",(i+1));
			int ccpID = obj->m_UserData->getAttributeAsInt(tmp_buf);
			if(ccpID>=0)
			{
				CSceneObject* ccp = getSceneObjectFromID(ccpID);
				const irr::core::vector3df& ccpPos1 = ccp->m_SceneNode->getAbsolutePosition();
				irr::core::vector3df targetOffset;
				targetOffset.set(ccp->m_UserData->getAttributeAsFloat("targetOffsetX"),
					ccp->m_UserData->getAttributeAsFloat("targetOffsetY"),
					ccp->m_UserData->getAttributeAsFloat("targetOffsetZ"));
				irr::core::vector3df targetPos1 = ccpPos1+targetOffset;

				sprintf_s(tmp_buf,"^Point%d^CamCtrlPoint",(next_idx+1));
				int nextccpID = obj->m_UserData->getAttributeAsInt(tmp_buf);
				if(nextccpID>=0)
				{
					CSceneObject* ccp2 = getSceneObjectFromID(nextccpID);
					const irr::core::vector3df& ccpPos2 = ccp2->m_SceneNode->getAbsolutePosition();				
					targetOffset.set(ccp2->m_UserData->getAttributeAsFloat("targetOffsetX"),
						ccp2->m_UserData->getAttributeAsFloat("targetOffsetY"),
						ccp2->m_UserData->getAttributeAsFloat("targetOffsetZ"));
					irr::core::vector3df targetPos2 = ccpPos2+targetOffset;

					SColor color_wp(255, 0, 0, 255);					
					g->driver->draw3DLine(targetPos1, targetPos2, color_wp);
				}
			}
		}
	}
}

void CLevelEditor::drawCameraAreaLinkLine(CSceneObject* obj)
{	
	char tmp_buf[512];
	const irr::core::vector3df& startPos = obj->m_SceneNode->getAbsolutePosition();
	for(int i=0; i<4; i++)
	{
		sprintf_s(tmp_buf,"^Next%d^CameraArea",(i+1));
		int linkID = obj->m_UserData->getAttributeAsInt(tmp_buf);
		if(linkID>=0)
		{
			CSceneObject* objNext= getSceneObjectFromID(linkID);
			if(objNext==0)
				continue;
			const irr::core::vector3df& endPos = objNext->m_SceneNode->getAbsolutePosition();
			SColor color_wp(255, 0, 255, 255);					
			g->driver->draw3DLine(startPos, endPos, color_wp);
		}
	}	
}

static SMeshBuffer s_CameraAreaMeshBuffer;

void CLevelEditor::drawCameraAreas()
{
	SMaterial matl;
	matl.Thickness = 2;
	matl.setFlag(EMF_LIGHTING, false);
	g->driver->setMaterial(matl);
	matrix4 mat;
    g->driver->setTransform(ETS_WORLD, mat);

	
	s_CameraAreaMeshBuffer.Indices.clear();
	s_CameraAreaMeshBuffer.Vertices.clear();

	//s_CameraAreaMeshBuffer.Material.MaterialType = irr::video::EMT_TRANSPARENT_TEXTURE_VERTEX_ALPHA;
	s_CameraAreaMeshBuffer.Material.MaterialType = irr::video::EMT_TRANSPARENT_VERTEX_ALPHA;
	
	s_CameraAreaMeshBuffer.Material.setFlag(EMF_BACK_FACE_CULLING, false);
	s_CameraAreaMeshBuffer.Material.setFlag(EMF_WIREFRAME, false);
	s_CameraAreaMeshBuffer.Material.setFlag(EMF_LIGHTING, false);
	s_CameraAreaMeshBuffer.Material.Thickness = 1;
	s_CameraAreaMeshBuffer.Material.setFlag(EMF_FOG_ENABLE, false);
	
	video::S3DVertex m_vertexBuffer[4];
	u16 m_indexBuffer[6] ;

	for (u32 i = 0; i < m_SceneObjects.size(); i ++)
	{
		if (m_SceneObjects[i]->m_type == E_OBJ_CAMERA_AREA)
		{
			if(!m_SceneObjects[i]->m_SceneNode->isVisible())
				continue;

			bool isSelected = isCameraAreaSelected(m_SceneObjects[i]);

			drawCameraAreaNormalRange(m_SceneObjects[i],isSelected);

			if(isSelected)
				drawCameraAreaLinkLine(m_SceneObjects[i]);

			std::vector<CSceneObject*> &ccps = getCameraAreaControlPoints(*this, m_SceneObjects[i]);			
			
			if(ccps.size()==4)
			{
				SColor color(128, 0, 255, 0);

				for(int ccpi=0; ccpi<4; ccpi++)
				{
					drawCCPDirectionLine(ccps[ccpi]);
					drawCCPTargetOffset(ccps[ccpi]);
					m_vertexBuffer[ccpi] = video::S3DVertex(ccps[ccpi]->m_SceneNode->getAbsolutePosition(), core::vector3df(0,0,0), color, core::vector2df(0.0f, 0.0f));
				}
																							
				m_indexBuffer[0] = 0;
				m_indexBuffer[1] = 1;
				m_indexBuffer[2] = 2;
				m_indexBuffer[3] = 0;
				m_indexBuffer[4] = 2;
				m_indexBuffer[5] = 3;

				s_CameraAreaMeshBuffer.append(m_vertexBuffer,4,m_indexBuffer,6);				
			}			
		}
	}

	g->driver->setMaterial(s_CameraAreaMeshBuffer.Material);
	//g->driver->drawVertexPrimitiveList(s_CameraAreaMeshBuffer.getVertices(), 
	//	s_CameraAreaMeshBuffer.getIndices(), 
	//	0,
	//	s_CameraAreaMeshBuffer.getVertexCount(),
	//	s_CameraAreaMeshBuffer.getIndexCount()/3, 
	//	video::EVT_STANDARD, 
	//	scene::EPT_TRIANGLES, 
	//	video::EIT_16BIT);	
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::drawGridWaypointConnections()
{
	//SMaterial matl;
	//matl.setFlag(EMF_LIGHTING, false);
	//g->driver->setMaterial(matl);
	//matrix4 mat;

 //   g->driver->setTransform(ETS_WORLD, mat);
	//

	//SMeshBuffer Buffer;
	//Buffer.Indices.clear();
	//Buffer.Vertices.clear();

	//Buffer.Material.setFlag(EMF_WIREFRAME, false);
	//Buffer.Material.setFlag(EMF_LIGHTING, false);
	//Buffer.Material.setThickness(1);
	//Buffer.Material.setFlag(EMF_FOG_ENABLE, false);
	//
	//video::S3DVertex m_vertexBuffer[3];// = new video::S3DVertex[3];
	//u16 m_indexBuffer[3] ;//= new u16[3];

	//for (u32 i = 0; i < m_SceneObjects.size(); i ++)
	//{
	//	
	//}

	//g->driver->drawVertexPrimitiveList(Buffer.getVertices(), 
	//	Buffer.getIndices(), 
	//	0,
	//	Buffer.getIndexCount(),
	//	Buffer.getVertexCount()/3, 
	//	video::EVT_STANDARD, 
	//	scene::EPT_TRIANGLES, 
	//	video::EIT_16BIT);
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::drawConnection(ISceneNode *pNode, int nextID, SMeshBuffer& Buffer , u16* m_indexBuffer , S3DVertex* m_vertexBuffer )
{
	vector3df start;
	vector3df end;

//	return;

	if (nextID >= 0)
	{
		start = pNode->getAbsolutePosition();
		//ISceneNode* nextNode = g->sceneManager->getSceneNodeFromId(nextID);
		//ms we loose 1 FPS here but it's better then 10 
		CSceneObject* obj = getSceneObjectFromID(nextID);
		if (obj)
		{
			ISceneNode* nextNode =	obj->m_SceneNode;
			if (nextNode)
			{			
				end = nextNode->getAbsolutePosition();
				SColor color_wp(255, 255, 0, 255);
				g->driver->draw3DLine(start, end, color_wp);

				vector3df dir = end - start;
				dir.normalize();

				vector3df normal = dir.crossProduct(end - g->sceneManager->getActiveCamera()->getPosition());
				normal.normalize();

				vector3df point1 = end - dir * 50;
				point1 += normal * 15;
				vector3df point2 = end - dir * 50;
				point2 -= normal * 15;

				triangle3df tri(end, point1, point2);
				SColor color(255, 255, 0, 0);
				//g->driver->draw3DTriangle(tri, color);

				m_vertexBuffer[0] = video::S3DVertex(end, core::vector3df(0,0,0), color, core::vector2df(0.0f, 0.0f));
				m_vertexBuffer[1] = video::S3DVertex(point1, core::vector3df(0,0,0), color, core::vector2df(0.0f, 0.0f));
				m_vertexBuffer[2] = video::S3DVertex(point2, core::vector3df(0,0,0), color, core::vector2df(0.0f, 0.0f));

				m_indexBuffer[0] = 0;
				m_indexBuffer[1] = 2;
				m_indexBuffer[2] = 1;

				Buffer.append(m_vertexBuffer,3,m_indexBuffer,3);

				//delete [] m_vertexBuffer;
				//delete [] m_indexBuffer;
			}
		}
	}
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::drawObjectSelectionHandles ()
{
	m_onScreenIds.set_used(0);
	m_onScreenPositions.set_used(0);
	m_selectedIndices.set_used(0);

	if (!g->eventReceiver->IsKeyDown(KEY_CONTROL))
		return;

	position2di mouse = g->device->getCursorControl()->getPosition();

	// find all objects with on screen center
	for (u32 i = 0; i < m_SceneObjects.size(); ++i)
	{
		if (m_SceneObjects[i]->m_SceneNode->getType() == ESNT_SKY_BOX)
			continue;

		vector2df pos2d;
		if (project3DTo2D(m_SceneObjects[i]->m_SceneNode->getAbsolutePosition(), &pos2d))
		{
			m_onScreenIds.push_back(m_SceneObjects[i]->m_SceneNode->getID());
			m_onScreenPositions.push_back(position2di((int)pos2d.X, (int)pos2d.Y));
		}
	}
	
	bool showDistance = g->getActiveCameraIndex()==CAMERA_XY;	
	float disRect[3];

	int x0 = mouse.X;
	int x1 = mouse.X;
	int y0 = mouse.Y;
	int y1 = mouse.Y;
	if (m_mouseDraggedWithCtrl)
	{
		x0 = m_mouseDragStart.X;
		x1 = mouse.X;
		y0 = m_mouseDragStart.Y;
		y1 = mouse.Y;
		if (x0 > x1) SWAP(x0, x1 , int);
		if (y0 > y1) SWAP(y0, y1 , int);

		SColor color(255, 0, 255, 0);
		g->driver->draw2DLine(position2di(x0, y0), position2di(x1, y0), color);
		g->driver->draw2DLine(position2di(x1, y0), position2di(x1, y1), color);
		g->driver->draw2DLine(position2di(x1, y1), position2di(x0, y1), color);
		g->driver->draw2DLine(position2di(x0, y1), position2di(x0, y0), color);

		
		if(showDistance)
		{	
			float _x0 = 0.0f, _y0 = 0.0f, _x1 = 0.0f, _y1 = 0.0f;
			irr::scene::ISceneCollisionManager* scm = g->sceneManager->getSceneCollisionManager();

			irr::core::plane3df plane(0,0,0,0,0,1);
			irr::core::vector3df pointOnXY;

			irr::core::line3df line1 = scm->getRayFromScreenCoordinates(irr::core::position2di(x0,y0),g->camera[CAMERA_XY]);
			plane.getIntersectionWithLine(line1.start, line1.getVector(), pointOnXY);						
			_x0 = pointOnXY.X;
			_y0 = pointOnXY.Y;

			irr::core::line3df line2 = scm->getRayFromScreenCoordinates(irr::core::position2di(x1,y1),g->camera[CAMERA_XY]);
			plane.getIntersectionWithLine(line2.start, line2.getVector(), pointOnXY);						
			_x1 = pointOnXY.X;
			_y1 = pointOnXY.Y;

			disRect[0] = abs(_x1-_x0);
			disRect[1] = abs(_y1-_y0);
			disRect[2] = sqrt(disRect[0]*disRect[0]+disRect[1]*disRect[1]);						
		}
	}

	int sz = 4;
	// draw selection handles
	for (u32 i = 0; i < m_onScreenPositions.size(); ++i)
	{
		int x = m_onScreenPositions[i].X;
		int y = m_onScreenPositions[i].Y;

		bool selected = false;
		if (m_mouseDraggedWithCtrl)
			selected = x >= x0 - sz && x <= x1 + sz && y >= y0 - sz && y <= y1 + sz;
		else
			selected = mouse.X >= x - sz && mouse.X <= x + sz && mouse.Y >= y - sz && mouse.Y <= y + sz;

		SColor color = selected ? SColor(255, 255, 255, 0) : SColor(255, 0, 255, 0);
		if (selected) m_selectedIndices.push_back(i);

		g->driver->draw2DRectangle(color, rect<s32>(x - sz, y - sz, x + sz, y + sz));

		color = SColor(255, 0, 127, 0);
		g->driver->draw2DLine(position2di(x - sz, y - sz), position2di(x + sz, y - sz), color);
		g->driver->draw2DLine(position2di(x + sz - 1, y - sz), position2di(x + sz - 1, y + sz - 1), color);
		g->driver->draw2DLine(position2di(x + sz - 1, y + sz - 1), position2di(x - sz, y + sz - 1), color);
		g->driver->draw2DLine(position2di(x - sz, y + sz - 1), position2di(x - sz, y - sz), color);
	}

	for (u32 i = 0; i < m_selection.size(); ++i)
	{
		vector2df screenPos;
		if (!project3DTo2D(m_selection[i]->m_SceneNode->getAbsolutePosition(), &screenPos)) continue;
		int x = (int)screenPos.X;
		int y = (int)screenPos.Y;

		SColor color = SColor(255, 255, 255, 0);
		g->driver->draw2DRectangle(color, rect<s32>(x - sz, y - sz, x + sz, y + sz));

		color = SColor(255, 0, 0, 0);
		g->driver->draw2DLine(position2di(x - sz, y - sz), position2di(x + sz, y - sz), color);
		g->driver->draw2DLine(position2di(x + sz - 1, y - sz), position2di(x + sz - 1, y + sz - 1), color);
		g->driver->draw2DLine(position2di(x + sz - 1, y + sz - 1), position2di(x - sz, y + sz - 1), color);
		g->driver->draw2DLine(position2di(x - sz, y + sz - 1), position2di(x - sz, y - sz), color);
	}

	bool left = mouse.X != x1;
	bool top = mouse.Y != y1;

	int y = mouse.Y;	

	for (u32 i = 0; i < m_selectedIndices.size(); ++i)
	{
		int idx = m_selectedIndices[i];
		CSceneObject* obj = getSceneObjectFromID(m_onScreenIds[idx]);
		stringw name = obj->m_UserData->getAttributeAsStringW("Name") +
			L"(" + stringw(obj->m_SceneNode->getID()) + L")";

		const dimension2d<u32> size = g->guienv->getSkin()->getFont()->getDimension(name.c_str());
		if (!top)
			y -= size.Height;
		int x = left ? x0 - size.Width - 13 : x1 + 13;
		position2di pos(x, y);

		rect<s32> rc(pos, size);
		rect<s32> rcbg(pos, size);
		rcbg.UpperLeftCorner.X -=2;
		rcbg.LowerRightCorner.X +=2;
		g->driver->draw2DRectangle(SColor(255,255,255,255),rcbg,&rcbg);
		g->guienv->getSkin()->getFont()->draw(name.c_str(), rc, SColor(255, 0, 0, 0));
		
		if (top)
			y += size.Height;
	}

	//draw selection rect distance	
	if(showDistance && m_mouseDraggedWithCtrl)
	{
		dimension2d<u32> size(g->guienv->getSkin()->getFont()->getDimension(L"H").Width, g->guienv->getSkin()->getFont()->getDimension(L"H").Height);
		int x = x0+(x1-x0)/2;
		int y = y0+(y1-y0)/2;
		y-=size.Height;

		for(int i=0; i<3; i++)
		{
			stringw str = (i==0)?L"DX:":((i==1)?L"DY:":L"DD:");
			str+= disRect[i];
			size.set(g->guienv->getSkin()->getFont()->getDimension(str.c_str()).Width, g->guienv->getSkin()->getFont()->getDimension(str.c_str()).Height);
			
			position2di pos(x-size.Width/2, y);

			rect<s32> rc(pos, size);
			rect<s32> rcbg(pos, size);
			rcbg.UpperLeftCorner.X -=2;
			rcbg.LowerRightCorner.X +=2;
			g->driver->draw2DRectangle(SColor(255,255,255,255),rcbg,&rcbg);
			g->guienv->getSkin()->getFont()->draw(str.c_str(), rc, SColor(255, 0, 0, 255));

			y += size.Height;
		}		
	}
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::drawPlayCinematicInfo()
{
	stringw str = L"Time:";
	str += m_cnm_currentTime;
	if(m_isCinematicPause)
	{
		str += L" ||";
	}

	const dimension2d<u32> size = g->guienv->getSkin()->getFont()->getDimension(str.c_str());
			
	int x = 10, y = 10;
	position2di pos(x, y);

	rect<s32> rc(pos, size);
	rect<s32> rcbg(pos, size);
	rcbg.UpperLeftCorner.X -=2;
	rcbg.LowerRightCorner.X +=2;
	g->driver->draw2DRectangle(SColor(255,255,255,255),rcbg,&rcbg);
	g->guienv->getSkin()->getFont()->draw(str.c_str(), rc, SColor(255, 0, 0, 255));		
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::drawCameraTarget()
{
    g->driver->setTransform(ETS_WORLD, matrix4());
	
	vector3df start;
	vector3df end;
	vector3df center;
	center = g->sceneManager->getActiveCamera()->getTarget();
	f32 size = (vector3df(g->sceneManager->getActiveCamera()->getPosition() - center).getLength()) / 25.0f;
	
	start = center - vector3df(size, 0.0f, 0.0f);
	end = center + vector3df(size, 0.0f, 0.0f);
	g->driver->draw3DLine(start, end, SColor(255, 0, 255, 255));

	start = center - vector3df(0.0f, 0.0f, size);
	end = center + vector3df(0.0f, 0.0f, size);
	g->driver->draw3DLine(start, end, SColor(255, 0, 255, 255));

	start = center - vector3df(0.0f, size, 0.0f);
	end = center + vector3df(0.0f, size, 0.0f);
	g->driver->draw3DLine(start, end, SColor(255, 0, 255, 255));
	//g->driver->beginScene2D();
	if (g->eventReceiver->IsKeyDown(KEY_TAB))
	{
		stringw name = L"(" ;
		name += center.X;
		name += L" , ";
		name += center.Y;
		name += L" , ";
		name += center.Z;
		name += L")"; 

		const dimension2d<u32> sSize = g->guienv->getSkin()->getFont()->getDimension(name.c_str());

		vector2df screenPos;
		
		rect<s32> viewport = g->driver->getViewPort();
		dimension2di dim = viewport.getSize() / 2;
		
		position2di pos( dim.Width, dim.Height);

		rect<s32> rc(pos, sSize);
		IGUIFont* pFont = g->guienv->getSkin()->getFont();
		const irr::core::dimension2d<u32> dimStr = pFont->getDimension(name.c_str());
		irr::core::rect<s32> rt;
		rt = irr::core::rect<s32>(pos, dimStr);
		g->driver->draw2DRectangle(SColor(255, 0, 0, 0),rt);
		g->guienv->getSkin()->getFont()->draw(name.c_str(), rc, SColor(255, 0, 255, 0));
	}
	//g->driver->endScene2D();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::insertChildren (map<CSceneObject*, bool>* isChild, CSceneObject* obj)
{
	TreeNode* node = ui->m_sceneGraphTree->FindNode(obj->m_SceneNode->getID());
	for (TreeNode* child = node->Child; child; child = child->Sibling)
	{
		CSceneObject* childObj = getSceneObjectFromID(child->ID);
		if (map<CSceneObject*, bool>::Node* node = isChild->find(childObj))
		{
			node->setValue(true);
		}
		else
		{
			isChild->insert(childObj, true);
			insertChildren(isChild, childObj);
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::removeReferences()
{
	for (u32 i=0; i < m_selection.size(); i++)
	{
		int id = m_selection[i]->m_SceneNode->getID();

		for (u32 j=0; j < m_SceneObjects.size(); j++)
		{
			if (m_selection[i] != m_SceneObjects[j])
			{
				for (u32 k=0; k < m_SceneObjects[j]->m_UserData->getAttributeCount(); k++)
				{
					const irr::c8* pName = m_SceneObjects[j]->m_UserData->getAttributeName(k);
					if (pName[0] == '^' && m_SceneObjects[j]->m_UserData->getAttributeAsInt(pName) == id)
					{
						m_SceneObjects[j]->m_UserData->setAttribute(pName, -1);
					}
				}
			}
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::checkReferentialIntegrity()
{
	bool bFound = false;
	stringw strReferences = L"";
	for (u32 i=0; i < m_selection.size(); i++)
	{
		int id = m_selection[i]->m_SceneNode->getID();

		for (u32 j=0; j < m_SceneObjects.size(); j++)
		{
			if (m_selection[i] != m_SceneObjects[j])
			{
				for (u32 k=0; k < m_SceneObjects[j]->m_UserData->getAttributeCount(); k++)
				{
					const irr::c8* pName = m_SceneObjects[j]->m_UserData->getAttributeName(k);
					if (pName[0] == '^' && m_SceneObjects[j]->m_UserData->getAttributeAsInt(pName) == id)
					{
						bFound = true;
						strReferences += stringw(m_SceneObjects[j]->m_SceneNode->getID()) +
							" - " + m_SceneObjects[j]->m_UserData->getAttributeAsStringW("Name") + stringw("\n");
					}
				}
			}
		}
	}

	if (bFound)
	{
		g->device->getGUIEnvironment()->addMessageBox(
			L"Warning" , (stringw(L"Object(s) referenced from :\n") + strReferences + stringw(L"\n Continue delete ? ")).c_str() , true , EMBF_YES | EMBF_NO, 0, MSG_BOX_CONFIRM_DELETE );

		return;
	}

	deleteSelectedNode();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::deleteSelectedNode()
{
	if (m_selection.size() == 1)
	{
		AddCommand(new CDeleteCommand(m_selection[0]));
	}
	else if (m_selection.size() > 1)
	{
		CMultiCommand* multi = new CMultiCommand;
		multi->setDescription(stringw(L"delete ") + stringw(m_selection.size()) + stringw(L" objects"));

		array<int> selectedIds;
		for (u32 i = 0; i < m_selection.size(); ++i)
			selectedIds.push_back(m_selection[i]->m_SceneNode->getID());
		CDeselectCommand* deselect = new CDeselectCommand(selectedIds);
		multi->addCommand(deselect);
		deselect->drop();

		for (u32 i = 0; i < m_selection.size(); ++i)
		{
			CDeleteCommand* del = new CDeleteCommand(m_selection[i]);
			multi->addCommand(del);
			del->drop();
		}

		AddCommand(multi);
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
int CLevelEditor::GetRoomID(ISceneNode *forSceneNode)
{
	TreeNode* treeNode = ui->m_sceneGraphTree->FindNode( forSceneNode->getID());
	
	int parentId;
	if (treeNode && treeNode->Parent)
	{
		parentId = treeNode->Parent->ID;
	}
	else
	{
		parentId = -1;
	}

	CSceneObject* sceneObject = NULL;
	
	while (parentId != -1)
	{
		sceneObject = getSceneObjectFromID(parentId);
		if (sceneObject->m_UserData->getAttributeAsString("!GameType") == "Geometry")
		{
			return parentId;
		}

		treeNode = treeNode->Parent;
		if (treeNode && treeNode->Parent)
		{
			parentId = treeNode->Parent->ID;
		}
		else
		{
			parentId = -1;
		}
	}

	return -1;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
IAttributes* CLevelEditor::createUserData(ISceneNode *forSceneNode)
{
	CSceneObject* sceneObject = getSceneObjectFromID(forSceneNode->getID());
	IAttributes* attr = g->device->getFileSystem()->createEmptyAttributes();
	
	m_SaveLoadProgress ++;
	//g->run();

	if (sceneObject)
	{
		TreeNode* treeNode = ui->m_sceneGraphTree->FindNode( forSceneNode->getID());
		int id;
		if (treeNode && treeNode->Parent)
			id = treeNode->Parent->ID;
		else
			id = -1;
		
		if (sceneObject->m_UserData->findAttribute("#ParentID") >= 0)
			sceneObject->m_UserData->setAttribute("#ParentID", id);
		else
			sceneObject->m_UserData->addInt("#ParentID", id);

		//int roomID = GetRoomID(forSceneNode);
		//if (sceneObject->m_UserData->findAttribute("#RoomID") >= 0)
		//	sceneObject->m_UserData->setAttribute("#RoomID", roomID);
		//else
		//	sceneObject->m_UserData->addInt("#RoomID", roomID);

		copyAttributes(attr, sceneObject->m_UserData);
		return attr;		
	}
	
	return 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::setSceneFileName(stringc newFileName)
{	
	m_SceneFilePath = g->device->getFileSystem()->getAbsolutePath(g->device->getFileSystem()->getFileDir(newFileName));
	m_SceneFileName = g->extractFileName(&newFileName);
	g->device->getFileSystem()->changeWorkingDirectoryTo(m_SceneFilePath.c_str());

	updateEditorCaption();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::copyAttributes(IAttributes* destination, IAttributes* source, int index, bool bOnlyIfExists)
{
	u32 startIndex, endIndex;
	if(index >= 0)
	{
		startIndex = index;
		endIndex = index + 1;
	}
	else
	{
		startIndex = 0;
		endIndex = source->getAttributeCount();
	}

	for (u32 i = startIndex; i < endIndex; i ++)
	{
		bool bAlreadyExists = destination->existsAttribute(source->getAttributeName(i));

		switch (source->getAttributeType(i))
		{
			case EAT_INT: 
				{
					if (bAlreadyExists)
					{
						destination->setAttribute(source->getAttributeName(i), 
								  source->getAttributeAsInt(i));
					}
					else if (!bOnlyIfExists)
					{
						destination->addInt(source->getAttributeName(i), 
								  source->getAttributeAsInt(i));
					}
				}
				break;

			case EAT_FLOAT: 
				{
					if (bAlreadyExists)
					{
						destination->setAttribute(source->getAttributeName(i), 
							  source->getAttributeAsFloat(i));
					}
					else if (!bOnlyIfExists)
					{
						destination->addFloat(source->getAttributeName(i), 
							  source->getAttributeAsFloat(i));
					}
				}
				break;

			case EAT_STRING: 
				{
					if (bAlreadyExists)
					{
						destination->setAttribute(source->getAttributeName(i), 
								 source->getAttributeAsString(i).c_str());
					}
					else if (!bOnlyIfExists)
					{
						destination->addString(source->getAttributeName(i), 
								 source->getAttributeAsString(i).c_str());
					}
				}
				break;

			case EAT_BOOL: 
				{
					if (bAlreadyExists)
					{
						destination->setAttribute(source->getAttributeName(i), 
							  source->getAttributeAsBool(i));
					}
					else if (!bOnlyIfExists)
					{
						destination->addBool(source->getAttributeName(i), 
							  source->getAttributeAsBool(i));
					}
				}
				break;

			case EAT_COLOR: 
				{
					if (bAlreadyExists)
					{
						destination->setAttribute(source->getAttributeName(i), 
							  source->getAttributeAsColor(i));
					}
					else if (!bOnlyIfExists)
					{
						destination->addColor(source->getAttributeName(i), 
							  source->getAttributeAsColor(i));
					}
				}
				break;

			case EAT_VECTOR3D: 
				{
					if (bAlreadyExists)
					{
						destination->setAttribute(source->getAttributeName(i), 
							  source->getAttributeAsVector3d(i));
					}
					else if (!bOnlyIfExists)
					{
						destination->addVector3d(source->getAttributeName(i), 
							  source->getAttributeAsVector3d(i));
					}
				}
				break;

			case EAT_QUATERNION:
				{
					if (bAlreadyExists)
					{
						destination->setAttribute(source->getAttributeName(i), 
							  source->getAttributeAsQuaternion(i));
					}
					else if (!bOnlyIfExists)
					{
						destination->addQuaternion(source->getAttributeName(i), 
							  source->getAttributeAsQuaternion(i));
					}
				}
				break;

			default:
				assert(0);
				break;
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::snapNode()
{
	//if (m_pCollisionTriSelector == NULL && m_physicalWorld->GetLowestRoot())
	//{
	//	g->guienv->addMessageBox(L"Error!", L"No collision loaded!", true);
	//	return;
	//}

	vector3df _finalPos_up;
	vector3df _finalPos_down;
	vector3df _direction_up(0, 0, 1000000);
	vector3df _direction_down(0, 0, -1000000);
	vector3df _error(0, 0, 1);

	for (u32 i = 0  ; i < m_selection.size() ; i++)
	{
		bool bFound = false;
	


		if(RayCollision(m_selection[i]->m_SceneNode->getAbsolutePosition() - _error, _direction_up, _finalPos_up))
		{
			bFound = true;
		}

		matrix4 matAbsTransform = m_selection[i]->m_SceneNode->getAbsoluteTransformation();

		if(RayCollision(m_selection[i]->m_SceneNode->getAbsolutePosition() + _error, _direction_down, _finalPos_down))
		{
			//select minimum distance
			if (bFound)
			{
				vector3df _position = m_selection[i]->m_SceneNode->getAbsolutePosition();
				if (abs(_position.Z - _finalPos_down.Z) <= abs(_position.Z - _finalPos_up.Z))
				{
					matAbsTransform.setTranslation(_finalPos_down);
					matrix4 matParentAbsTransform = m_selection[i]->m_SceneNode->getParent()->getAbsoluteTransformation();
					matParentAbsTransform.makeInverse();
					m_selection[i]->m_SceneNode->setRelativeTransformation(matParentAbsTransform * matAbsTransform);
					//force update
					m_selection[i]->m_SceneNode->setPosition(m_selection[i]->m_SceneNode->getPosition());
				}
				else
				{
					matAbsTransform.setTranslation(_finalPos_up);
					matrix4 matParentAbsTransform = m_selection[i]->m_SceneNode->getParent()->getAbsoluteTransformation();
					matParentAbsTransform.makeInverse();
					m_selection[i]->m_SceneNode->setRelativeTransformation(matParentAbsTransform * matAbsTransform);
					//force update
					m_selection[i]->m_SceneNode->setPosition(m_selection[i]->m_SceneNode->getPosition());
				}
			}
			else
			{
				matAbsTransform.setTranslation(_finalPos_down);
				matrix4 matParentAbsTransform = m_selection[i]->m_SceneNode->getParent()->getAbsoluteTransformation();
				matParentAbsTransform.makeInverse();
				m_selection[i]->m_SceneNode->setRelativeTransformation(matParentAbsTransform * matAbsTransform);
				//force update
				m_selection[i]->m_SceneNode->setPosition(m_selection[i]->m_SceneNode->getPosition());
				bFound = true;
			}
		}
		else if (bFound)
		{
			matAbsTransform.setTranslation(_finalPos_up);
			matrix4 matParentAbsTransform = m_selection[i]->m_SceneNode->getParent()->getAbsoluteTransformation();
			matParentAbsTransform.makeInverse();
			m_selection[i]->m_SceneNode->setRelativeTransformation(matParentAbsTransform * matAbsTransform);
			//force update
			m_selection[i]->m_SceneNode->setPosition(m_selection[i]->m_SceneNode->getPosition());
		}

		if (!bFound)
		{
			stringw msg = L"No collision detected! Node : ";
			msg += m_selection[i]->m_SceneNode->getID();
			g->guienv->addMessageBox(L"Error!", msg.c_str(), true);
		}
	}

	
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::addObjectToTreeView(CSceneObject* obj, int parentNodeID)
{
	stringw name = stringw(obj->m_SceneNode->getID());
	name += " - ";
	name += obj->m_UserData->getAttributeAsStringW("Name");
	if(parentNodeID>=0)
	{
		TreeNode* parentTreeNode = ui->m_sceneGraphTree->FindNode(parentNodeID);
		irr::gui::CGUITreeCtrl* treeCtrl = static_cast<irr::gui::CGUITreeCtrl*>(ui->m_sceneGraphTree);
		treeCtrl->InsertToParentNode(parentTreeNode, name, obj->m_SceneNode->getID(), obj);	
	}
	else
	{
		ui->m_sceneGraphTree->InsertToSelectedNode(name, obj->m_SceneNode->getID(), obj);	
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::AddInsertCommand (CSceneObject* object)
{
	stringw name = object->m_UserData->getAttributeAsStringW("Name");
	int id = object->m_SceneNode->getID();
	bool bVisible = object->m_SceneNode->isVisible();

	IDoUndoCommand* del = new CDeleteCommand(object);
	del->redo();
	IDoUndoCommand* command = del->getReverse();
	del->drop();
	command->setDescription(stringw(L"insert ") + name + L"(" + stringw(id) + L")");
	AddCommand(command);
	ui->setSceneNodeVisible(id ,bVisible);
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
ISceneNode* CLevelEditor::GetParentFromSelection(stringc gameType)
{
	if (m_selection.size() > 0)
	{
		ISceneNode* pNode = m_selection[0]->m_SceneNode;
		
		bool bParentIsRoot = false;

		if (gameType == "NavMesh" || gameType == "Collisions")
		{
			bParentIsRoot = true;
		}

		while (pNode)
		{
			CSceneObject* pObj = getSceneObjectFromID(pNode->getID());
			if (pObj && gameType == "DropObject" && 
				pObj->m_UserData->getAttributeAsString("!GameType") == "DropArea")
			{
				setSelectedNode(pNode);
				return pNode;
			}
			if (pObj && gameType == "RestorePoint" && 
				pObj->m_UserData->getAttributeAsString("!GameType") == "TriggerRestore")
			{
				setSelectedNode(pNode);
				return pNode;
			}
			if (pObj && (pObj->m_UserData->getAttributeAsString("!GameType") == "Geometry" ||
				pObj->m_UserData->getAttributeAsString("!GameType") == "Group"  ||				
				pObj->m_UserData->getAttributeAsString("!GameType") == "EnemyGroup" ))
			{
				setSelectedNode(pNode);

				if (!bParentIsRoot && pObj->m_UserData->getAttributeAsString("!GameType") == "Geometry")
				{
					ISceneNode* pRefNode = GetRoomRefNode(pNode);
					if (!pRefNode)
					{
						setSelectedNode(NULL);
					}
					//else if (pRefNode->getScale() != vector3df(1.0f, 1.0f, 1.0f) || !(pRefNode->getRotation() == quaternion()))
					else if (pRefNode->getScale() != vector3df(1.0f, 1.0f, 1.0f) || !(pRefNode->getRotation() == core::vector3df()))
					{
						pRefNode->setScale(vector3df(1.0f, 1.0f, 1.0f));
						pRefNode->setRotation(core::vector3df());

						g->device->getGUIEnvironment()->addMessageBox(
								L"Warning" , (stringw(L"Use Reset XForm for geometry \"") + pRefNode->getName() + stringw(L"\"")).c_str());
					}
					return pRefNode;
				}
				else
				{
					return pNode;
				}
			}

			pNode = pNode->getParent();
		}
	}

	setSelectedNode(NULL);
	return NULL;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::SetEnemyType(ISceneNode* node, int type)
{
	
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
CSceneObject* CLevelEditor::createGameObject(CGameObject *pTemplate , s32 Id, bool bPositionObj , bool bLoading, int parentID)
{
	if (Id == -1 && m_lastUniqueId >= m_maxId - 1)
	{
		g->guienv->addMessageBox(L"Error!", L"Message ID reached limit!!! \nChange the range of ids in 'editor_config.xml' to be able to add objects!!!", true);
		return NULL;
	}

	bool doAutoCreateCamCtrlPoints = false;
	bool doAutoCreateWayPoint = false;
	bool doAutoCreateEffect = false;

	ISceneNode* node = 0;
	
	g->device->getFileSystem()->changeWorkingDirectoryTo(m_SceneFilePath.c_str());

	stringc gameType = pTemplate->m_Attributes->getAttributeAsString("!GameType");

	if (gameType == "Trigger" || gameType == "Cover" || gameType == "TriggerSound")
	{
		node = createGameTrigger(pTemplate);
	}
	else if( gameType == "EffectDamage" )
	{
		node = createGameTrigger(pTemplate);	
	}
	else if( gameType == "CheckPoint" )
	{
		node = createGameTrigger(pTemplate);	
	}
	else if (gameType == "DropArea")
	{
		node = createGameTrigger(pTemplate);
	}
	else if (gameType == "DropObject")
	{
		ISceneNode* pNode = m_selection[0]->m_SceneNode;
		CSceneObject* pObj = getSceneObjectFromID(pNode->getID());
		if (!pObj || pObj->m_UserData->getAttributeAsString("!GameType") != "DropArea")
			return NULL;
		//node = createEmptySceneNode(pTemplate);
		node = g->sceneManager->addEmptySceneNode(NULL);
		//if(!bLoading)
		//	doAutoCreateCamCtrlPoints = true;
	}
	else if (gameType == "TriggerRestore")
	{
		node = createGameTrigger(pTemplate);
		if(!bLoading)
			doAutoCreateWayPoint= true;
	}
	else if (gameType == "RestorePoint")
		node = g->sceneManager->addEmptySceneNode(NULL);

	else if (gameType == "CameraArea")
	{
		node = createCameraArea(pTemplate);
		if(!bLoading)
			doAutoCreateCamCtrlPoints = true;
	}
	else if (gameType == "CamCtrlPoint")
	{
		node = g->sceneManager->addEmptySceneNode(NULL);
	}
	else if (gameType == "CameraDirCtl")
	{
		node = createCameraDirCtl(pTemplate);
	}
	else
	{
		node = createEmptySceneNode(pTemplate);
	}

	if (node)
	{
		node->setID(getUniqueSceneObjectID(Id));

		if (pTemplate->m_Attributes->findAttribute("#MeshFile") >= 0)
		{
			ISceneNode* pNode = NULL;//ConstructColladaScene(pTemplate->m_Attributes->getAttributeAsString("#MeshFile").c_str());
			if (pNode)
			{
				node->addChild(pNode);
				//SetMaterialFlag(pNode, EMF_LIGHTING, false);
			}
		}
	
		if (pTemplate->m_Attributes->findAttribute("MaterialType") >= 0)	
		{
			if (node->getMaterialCount() > 0)
			{
				stringw mStr = pTemplate->m_Attributes->getAttributeAsStringW("MaterialType");
				for (int z = 0; z < g->device->getVideoDriver()->getMaterialRendererCount(); z ++)
					if (mStr == g->device->getVideoDriver()->getMaterialRendererName(z))
					{
						node->getMaterial(0).MaterialType = (E_MATERIAL_TYPE)z;
						break;
					}
			}
		}

		CSceneObject* sceneObject = new CSceneObject();		
		sceneObject->m_SceneNode = node;			
		sceneObject->m_SceneNode->grab();

		if (bPositionObj && pTemplate->m_Attributes->findAttribute("!GameType") >= 0 && 
			( 
				(pTemplate->m_Attributes->getAttributeAsString("!GameType") != "Geometry") &&	
				(pTemplate->m_Attributes->getAttributeAsString("!GameType") != "Collisions") &&	
				(pTemplate->m_Attributes->getAttributeAsString("!GameType") != "NavMesh") &&
				(pTemplate->m_Attributes->getAttributeAsString("!GameType") != "Skybox") &&
				(pTemplate->m_Attributes->getAttributeAsString("!GameType") != "Group")
			)
		   )
		{
			bool bFound = false;
			position2di mousePos = g->device->getCursorControl()->getPosition();
			
			ISceneCollisionManager* colmgr = g->sceneManager->getSceneCollisionManager();

			line3df ray = colmgr->getRayFromScreenCoordinates(mousePos, g->sceneManager->getActiveCamera());
			m_screenRay = ray;

			//check intersection with collisions
			//if (m_pCollisionTriSelector != NULL)
			{
				vector3df finalPos;
				if(RayCollision(ray.start, ray.end - ray.start, finalPos, true))
				{
					ISceneNode* pParent = node->getParent();
					
					if (pParent)
					{
						matrix4 matAbsTransform = node->getAbsoluteTransformation();
						matAbsTransform.setTranslation(finalPos);
						matrix4 matParentAbsTransform = pParent->getAbsoluteTransformation();
						matParentAbsTransform.makeInverse();
						node->setRelativeTransformation(matParentAbsTransform * matAbsTransform);
					}
					else
					{
						node->setPosition(finalPos);
					}

					bFound = true;
				}
			}

			//check intersection with grid
			if (!bFound)
			{
				f32 gridSize = (f32)g->m_gridSize / 2.0f;
				triangle3df tri1(vector3df(-gridSize, -gridSize, 0), vector3df(-gridSize, gridSize, 0), vector3df(gridSize, gridSize, 0));
				triangle3df tri2(vector3df(-gridSize, -gridSize, 0), vector3df(gridSize, -gridSize, 0), vector3df(gridSize, gridSize, 0));

				vector3df outInter;
				if (tri1.getIntersectionWithLimitedLine(ray, outInter))
				{
					ISceneNode* pParent = node->getParent();
					
					if (pParent)
					{
						matrix4 matAbsTransform = node->getAbsoluteTransformation();
						matAbsTransform.setTranslation(outInter);
						matrix4 matParentAbsTransform = pParent->getAbsoluteTransformation();
						matParentAbsTransform.makeInverse();
						node->setRelativeTransformation(matParentAbsTransform * matAbsTransform);
					}
					else
					{
						node->setPosition(outInter);
					}

					bFound = true;
				}
				else if (tri2.getIntersectionWithLimitedLine(ray, outInter))
				{
					ISceneNode* pParent = node->getParent();
					
					if (pParent)
					{
						matrix4 matAbsTransform = node->getAbsoluteTransformation();
						matAbsTransform.setTranslation(outInter);
						matrix4 matParentAbsTransform = pParent->getAbsoluteTransformation();
						matParentAbsTransform.makeInverse();
						node->setRelativeTransformation(matParentAbsTransform * matAbsTransform);
					}
					else
					{
						node->setPosition(outInter);
					}

					bFound = true;
				}
			}

			if (!bFound)
			{
				SetPositionInFrontOfTheCamera(node);
			}
		}

		copyAttributes(sceneObject->m_UserData, pTemplate->m_Attributes);

		bool bFound = false;
		for (u32 i=0; i < m_SceneObjects.size(); i++)
		{
			if (sceneObject->m_SceneNode->getID() < m_SceneObjects[i]->m_SceneNode->getID())
			{
				m_SceneObjects.insert(sceneObject, i);
				bFound = true;
				break;
			}
		}

		if (!bFound) 
			m_SceneObjects.push_back(sceneObject);
		
		addObjectToTreeView(sceneObject, parentID);

		//AddInsertCommand(sceneObject);

		sceneObject->ProcessAttributes();//WuHao:To fix bug new created node don't init some property, such as new way point don't show line

		if(doAutoCreateCamCtrlPoints)
		{
			autoCreateCamCtrlPoints(sceneObject);
		}
		if (doAutoCreateWayPoint)
		{
			autoCreateWayPoint(sceneObject);
		}
		if (gameType == "DropObject")
		{
			ISceneNode* pNode = m_selection[0]->m_SceneNode;
			CSceneObject* pObj = getSceneObjectFromID(pNode->getID());
			
			sceneObject->m_UserData->setAttribute("!^Owner^DropArea", pObj->m_SceneNode->getID());
		}
		return sceneObject;
	}

	return NULL;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
CSceneObject* CLevelEditor::createGameObject(u32 index , s32 Id, bool bPositionObj, bool bLoading)
{
	return createGameObject(m_GameObjects[index], Id, bPositionObj, bLoading);
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
ISceneNode* CLevelEditor::createGameTrigger(CGameObject* objTemplate)
{
	ISceneNode* node = 0;

	vector3df sizes = objTemplate->m_Attributes->getAttributeAsVector3d("Sizes");
	
	node = g->sceneManager->addMeshSceneNode( 0 , GetParentFromSelection(objTemplate->m_Attributes->getAttributeAsString("!GameType")) , -1 , vector3df(0,0,0) , vector3df(0,0,0) , vector3df(1,1,1) , true );	
	IMesh* mesh = createMeshWithSize(sizes);
	((IMeshSceneNode*)node)->setMesh(mesh);
	mesh->drop();

	return node;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
ISceneNode* CLevelEditor::createCameraArea(CGameObject* objTemplate)
{
	ISceneNode* node = 0;

	node = g->sceneManager->addEmptySceneNode( GetParentFromSelection(objTemplate->m_Attributes->getAttributeAsString("!GameType")));		
	
	return node;		
}
void CLevelEditor::preprocessCreateCameraArea(CGameObject* objTemplate)
{
	m_caRefVecs.clear();

	stringc gameType = objTemplate->m_Attributes->getAttributeAsString("!GameType");

	if(gameType=="CameraArea" && m_selection.size()==2)
	{				
		CSceneObject* pSelObj1 = m_selection[0];
		CSceneObject* pSelObj2 = m_selection[1];
		
		if(pSelObj1->m_type==E_OBJ_CAM_CTRL_POINT && pSelObj2->m_type==E_OBJ_CAM_CTRL_POINT)
		{
			int ownerCA1 = pSelObj1->m_UserData->getAttributeAsInt("!^Owner^CameraArea");
			if(ownerCA1!=-1)
			{
				int ownerCA2 = pSelObj2->m_UserData->getAttributeAsInt("!^Owner^CameraArea");
				if(ownerCA1==ownerCA2)
				{
					CSceneObject * refCameraArea = getSceneObjectFromID(ownerCA1);

					char strBuf[256];
					int ccpid = -1;
					for(int i=0; i<4; i++)
					{
						sprintf_s(strBuf,"^Point%d^CamCtrlPoint",(i+1));
						ccpid = refCameraArea->m_UserData->getAttributeAsInt(strBuf);
						if(ccpid!=pSelObj1->m_SceneNode->getID() && ccpid!=pSelObj2->m_SceneNode->getID())
							break;
					}

					if(ccpid==-1)
						return;

					CSceneObject* thirdPoint = getSceneObjectFromID(ccpid);

					const irr::core::vector3df& pos1 = pSelObj1->m_SceneNode->getPosition();
					const irr::core::vector3df& pos2 = pSelObj2->m_SceneNode->getPosition();
					const irr::core::vector3df& pos3 = thirdPoint->m_SceneNode->getPosition();
					
					irr::core::vector3df vec31 = pos1-pos3;						
					irr::core::vector3df vec12 = pos2-pos1;
					irr::f32 vec12_len = vec12.getLength();
					vec12.normalize();

					irr::core::vector3df projVec = vec12 * vec12.dotProduct(vec31);
					irr::core::vector3df dirVec = (vec31-projVec);
					dirVec.normalize();
					dirVec*=vec12_len;

					// [0] pos1, [1] pos2, [2] dirVec, 
					// [3] point1 cam dir, [4] point2 cam dir, [5] X: point1 cam dis Y: point2 cam dis
					// [6] target offset1 [7] target offset2
					// [8]  X:point 1 target height off, Y:point 2 target height
					m_caRefVecs.push_back(pos1);
					m_caRefVecs.push_back(pos2);
					m_caRefVecs.push_back(dirVec);
					m_caRefVecs.push_back(irr::core::vector3df(
						pSelObj1->m_UserData->getAttributeAsFloat("dx"),
						pSelObj1->m_UserData->getAttributeAsFloat("dy"),
						pSelObj1->m_UserData->getAttributeAsFloat("dz"))
						);
					m_caRefVecs.push_back(irr::core::vector3df(
						pSelObj2->m_UserData->getAttributeAsFloat("dx"),
						pSelObj2->m_UserData->getAttributeAsFloat("dy"),
						pSelObj2->m_UserData->getAttributeAsFloat("dz"))
						);
					m_caRefVecs.push_back(irr::core::vector3df(
						pSelObj1->m_UserData->getAttributeAsFloat("dis"),
						pSelObj2->m_UserData->getAttributeAsFloat("dis"),
						0.0f)
						);
					m_caRefVecs.push_back(irr::core::vector3df(
						pSelObj1->m_UserData->getAttributeAsFloat("targetOffsetX"),
						pSelObj1->m_UserData->getAttributeAsFloat("targetOffsetY"),
						pSelObj1->m_UserData->getAttributeAsFloat("targetOffsetZ"))
						);
					m_caRefVecs.push_back(irr::core::vector3df(
						pSelObj2->m_UserData->getAttributeAsFloat("targetOffsetX"),
						pSelObj2->m_UserData->getAttributeAsFloat("targetOffsetY"),
						pSelObj2->m_UserData->getAttributeAsFloat("targetOffsetZ"))
						);
					m_caRefVecs.push_back(irr::core::vector3df(
						pSelObj1->m_UserData->getAttributeAsFloat("targetHeightOff"),
						pSelObj2->m_UserData->getAttributeAsFloat("targetHeightOff"),
						0.0f)
						);
				}
			}
		}
	}
}

void CLevelEditor::autoCreateWayPoint(CSceneObject* pTriggerRestoreObj)
{
	if (m_restorePointTemplate != 0)
	{
		int parentID = pTriggerRestoreObj->m_SceneNode->getID();
		CSceneObject* pWayPointObj = createGameObject(m_restorePointTemplate, -1, false, false, parentID);

		pWayPointObj->m_SceneNode->setPosition(pTriggerRestoreObj->m_SceneNode->getPosition());
		pWayPointObj->InitAttributes();
		
		pTriggerRestoreObj->m_UserData->setAttribute("^Link^RestorePoint", pWayPointObj->m_SceneNode->getID());
	}
}
void CLevelEditor::autoCreateCamCtrlPoints(CSceneObject* cameraAreaObj)
{
	if(m_camCtrlPointTemplate!=0)
	{
		//auto create camCtrlPoint and link
		for(int i=0; i<4; i++)
		{
			int caNodeID = cameraAreaObj->m_SceneNode->getID();
			CSceneObject* camCtrlPointObj = createGameObject(m_camCtrlPointTemplate, -1, false, false, caNodeID);

			if(cameraAreaObj->m_SceneNode->getParent())
			{
				cameraAreaObj->m_SceneNode->getParent()->addChild(camCtrlPointObj->m_SceneNode);
			}

			camCtrlPointObj->InitAttributes();

			//link ccp and ca eachother
			camCtrlPointObj->m_UserData->setAttribute("!^Owner^CameraArea", cameraAreaObj->m_SceneNode->getID());
			char attr_name_buf[512];
			sprintf_s(attr_name_buf,"^Point%d^CamCtrlPoint", (i+1));
			cameraAreaObj->m_UserData->setAttribute(attr_name_buf, camCtrlPointObj->m_SceneNode->getID());

			
			if(m_caRefVecs.size()==0)
			{
				irr::core::vector3df pos = cameraAreaObj->m_SceneNode->getPosition();
				if(i==0)
				{
					pos.X-=500;
					pos.Y+=500;
				}
				else if(i==1)
				{
					pos.X-=500;
					pos.Y-=500;
				}
				else if(i==2)
				{
					pos.X+=500;
					pos.Y-=500;
				}
				else
				{
					pos.X+=500;
					pos.Y+=500;
				}

				//set ccp pos
				camCtrlPointObj->m_SceneNode->setPosition(pos);													
			}
			else
			{
				if(i==0)
				{
					camCtrlPointObj->m_SceneNode->setPosition(m_caRefVecs.at(0));
					camCtrlPointObj->m_UserData->setAttribute("dx", m_caRefVecs[3].X);
					camCtrlPointObj->m_UserData->setAttribute("dy", m_caRefVecs[3].Y);
					camCtrlPointObj->m_UserData->setAttribute("dz", m_caRefVecs[3].Z);
					camCtrlPointObj->m_UserData->setAttribute("dis", m_caRefVecs[5].X);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetX",m_caRefVecs[6].X);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetY",m_caRefVecs[6].Y);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetZ",m_caRefVecs[6].Z);
					camCtrlPointObj->m_UserData->setAttribute("targetHeightOff",m_caRefVecs[8].X);
				}
				else if(i==1)
				{
					camCtrlPointObj->m_SceneNode->setPosition(m_caRefVecs.at(1));
					camCtrlPointObj->m_UserData->setAttribute("dx", m_caRefVecs[4].X);
					camCtrlPointObj->m_UserData->setAttribute("dy", m_caRefVecs[4].Y);
					camCtrlPointObj->m_UserData->setAttribute("dz", m_caRefVecs[4].Z);
					camCtrlPointObj->m_UserData->setAttribute("dis", m_caRefVecs[5].Y);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetX",m_caRefVecs[7].X);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetY",m_caRefVecs[7].Y);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetZ",m_caRefVecs[7].Z);
					camCtrlPointObj->m_UserData->setAttribute("targetHeightOff",m_caRefVecs[8].Y);
				}
				else if(i==2)
				{
					camCtrlPointObj->m_SceneNode->setPosition(m_caRefVecs.at(1)+m_caRefVecs.at(2));
					camCtrlPointObj->m_UserData->setAttribute("dx", m_caRefVecs[4].X);
					camCtrlPointObj->m_UserData->setAttribute("dy", m_caRefVecs[4].Y);
					camCtrlPointObj->m_UserData->setAttribute("dz", m_caRefVecs[4].Z);
					camCtrlPointObj->m_UserData->setAttribute("dis", m_caRefVecs[5].Y);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetX",m_caRefVecs[7].X);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetY",m_caRefVecs[7].Y);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetZ",m_caRefVecs[7].Z);
					camCtrlPointObj->m_UserData->setAttribute("targetHeightOff",m_caRefVecs[8].Y);
				}
				else
				{
					camCtrlPointObj->m_SceneNode->setPosition(m_caRefVecs.at(0)+m_caRefVecs.at(2));
					camCtrlPointObj->m_UserData->setAttribute("dx", m_caRefVecs[3].X);
					camCtrlPointObj->m_UserData->setAttribute("dy", m_caRefVecs[3].Y);
					camCtrlPointObj->m_UserData->setAttribute("dz", m_caRefVecs[3].Z);
					camCtrlPointObj->m_UserData->setAttribute("dis", m_caRefVecs[5].X);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetX",m_caRefVecs[6].X);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetY",m_caRefVecs[6].Y);
					camCtrlPointObj->m_UserData->setAttribute("targetOffsetZ",m_caRefVecs[6].Z);
					camCtrlPointObj->m_UserData->setAttribute("targetHeightOff",m_caRefVecs[8].X);

					//set camera area object pos
					irr::core::vector3df caNewPos = (m_caRefVecs.at(0)+m_caRefVecs.at(1))/2 + m_caRefVecs.at(2)/2;
					cameraAreaObj->m_SceneNode->setPosition(caNewPos);
					cameraAreaObj->m_SceneNode->OnAnimate(0);						
				}
			}
			
			camCtrlPointObj->m_SceneNode->OnAnimate(0);				
		}

		if(m_caRefVecs.size()!=0)
			CorrectSelectedCameraArea();
	}
}

void CLevelEditor::MoveObject(bool begin,CSceneObject* pObj,CCinematicCommand* cmd, int nowTime, bool posOnly)
{
	if( begin )
	{
		if( pObj == NULL )
		{
			g->guienv->addMessageBox(L"Error!", L"Please Link ONE object first!!!", true);
			return;
		}

		irr::core::vector3df pos = cmd->m_Attributes->getAttributeAsVector3d("pos");
		if(!posOnly || pos!=irr::core::vector3df(0,0,0))	
			pObj->m_SceneNode->setPosition(pos);
						
		if(!posOnly)
		{			
			irr::core::quaternion rot = cmd->m_Attributes->getAttributeAsQuaternion("rot");
			core::vector3df rotate;
			rot.toEuler(rotate);
			pObj->m_SceneNode->setRotation(rotate);
		}

		pObj->m_SceneNode->updateAbsolutePosition();

		ui->m_CinematicEditor.m_Active = false;

		m_cnm_obj_moved = pObj;
		m_cnm_objmove_cmd = cmd;

		ui->m_CinematicEditor.SetVisible(false);
		editor->setSelectedNode(pObj->m_SceneNode);
		m_isMovingObject = true;

		PlayCinematicToTime(nowTime);
	}
	else
	{
		ui->m_CinematicEditor.m_Active = true;

		ui->m_CinematicEditor.SetVisible(true);
		m_isMovingObject = false;

		//write back obj data
		irr::core::vector3df pos = m_cnm_obj_moved->m_SceneNode->getPosition();
		m_cnm_objmove_cmd->m_Attributes->setAttribute("pos",pos);

		if(m_cnm_objmove_cmd->m_Name=="PlayEffect")
			posOnly = true;

		if(!posOnly)
		{
			irr::core::quaternion rot =  m_cnm_obj_moved->m_SceneNode->getRotation();			
			m_cnm_objmove_cmd->m_Attributes->setAttribute("rot",rot);
		}

		m_cnm_objmove_cmd->m_Attributes->setAttribute("abspos",m_cnm_obj_moved->m_SceneNode->getAbsolutePosition());
			
		ui->m_CinematicEditor.updateProperties();		
	}
}


void CLevelEditor::ChangeCamera(bool begin, bool cancelEdit, CCinematicCommand* cmd, int nowTime)
{
	if( begin )
	{						
		CChangeCameraAnimator* anim = (CChangeCameraAnimator*)*g->camera[CHANGE_CAMERA]->getAnimators().begin();
						
		anim->SetCameraInfo(cmd);
		
		g->setActiveCamera(CHANGE_CAMERA);

		PlayCinematicToTime(nowTime);

		g->OnOffDeviceEmulatorMode(true);
		
	}
	else
	{
		if(!cancelEdit)
		{
			CChangeCameraAnimator* anim = (CChangeCameraAnimator*)*g->camera[CHANGE_CAMERA]->getAnimators().begin();
			anim->SaveCameraInfoToCinematic();
		}

		g->setActiveCamera(MAYA_CAMERA);

		g->OnOffDeviceEmulatorMode(false);
	}
}

void CLevelEditor::OnOffCameraModeCtrlPoint(bool on, bool cancelEdit)
{	
	if(on)
	{
		do
		{
			if (m_selection.size()!=1)
			{			
				break;
			}		

			CSceneObject* pObj = m_selection[0];
			
			if(pObj->m_type != E_OBJ_CAM_CTRL_POINT)
			{
				break;
			}		

			CCtrolPointCameraAnimator* anim = (CCtrolPointCameraAnimator*)*g->camera[CONTROL_POINT_CAMERA]->getAnimators().begin();
			anim->initControlPointCameras(pObj);

			g->setActiveCamera(CONTROL_POINT_CAMERA);			

			g->OnOffDeviceEmulatorMode(true);

			return;
		}
		while(0);

		stringw strError = L"";	
		strError += L"Please select ONE CamCtrlPoint object first!";
		
		g->guienv->addMessageBox(L"Error!", strError.c_str(), true);
		ui->m_SetCameraButton->setPressed(false);
		
	}
	else
	{
		CCtrolPointCameraAnimator* anim = (CCtrolPointCameraAnimator*)*g->camera[CONTROL_POINT_CAMERA]->getAnimators().begin();
		if(!cancelEdit)
			anim->saveToCamCtrlPointObjects();
		
		irr::scene::ISceneNode* ctrlPointNode = anim->getCurrentControlPointNode();
		
		anim->freeControlPointCameras();
		g->setActiveCamera(MAYA_CAMERA);

		if(ctrlPointNode!=0)
		{
			editor->setSelectedNode(ctrlPointNode);
			extern void focusCameraOn (ISceneNode* node);
			focusCameraOn(ctrlPointNode);
		}

		g->OnOffDeviceEmulatorMode(false);
	}
}

void CLevelEditor::CopySelectedCameraPoint(bool doCopy)
{	
	do
	{
		if (m_selection.size()!=2)
		{			
			break;
		}		
		
		if(m_selection[0]->m_type != E_OBJ_CAM_CTRL_POINT
			|| m_selection[1]->m_type != E_OBJ_CAM_CTRL_POINT)
		{
			break;
		}

		if(doCopy)
		{
			if(m_ckb_cpycam_pos && m_ckb_cpycam_pos->isChecked())
			{
				irr::core::vector3df absPos = m_selection[0]->m_SceneNode->getAbsolutePosition();
				irr::scene::ISceneNode* pParent = m_selection[1]->m_SceneNode->getParent();
				if(pParent)
				{
					pParent->updateAbsolutePosition();
					m_selection[1]->m_SceneNode->setPosition(absPos - pParent->getAbsolutePosition());					
				}
				else
				{
					m_selection[1]->m_SceneNode->setPosition(absPos);
				}								
			}
			
			if(m_ckb_cpycam_cam && m_ckb_cpycam_cam->isChecked())
			{
				m_selection[1]->m_UserData->setAttribute("dx", m_selection[0]->m_UserData->getAttributeAsFloat("dx"));
				m_selection[1]->m_UserData->setAttribute("dy", m_selection[0]->m_UserData->getAttributeAsFloat("dy"));
				m_selection[1]->m_UserData->setAttribute("dz", m_selection[0]->m_UserData->getAttributeAsFloat("dz"));
				m_selection[1]->m_UserData->setAttribute("dis", m_selection[0]->m_UserData->getAttributeAsFloat("dis"));
			}

			if(m_ckb_cpycam_target && m_ckb_cpycam_target->isChecked())
			{
				m_selection[1]->m_UserData->setAttribute("targetOffsetX", m_selection[0]->m_UserData->getAttributeAsFloat("targetOffsetX"));
				m_selection[1]->m_UserData->setAttribute("targetOffsetY", m_selection[0]->m_UserData->getAttributeAsFloat("targetOffsetY"));
				m_selection[1]->m_UserData->setAttribute("targetOffsetZ", m_selection[0]->m_UserData->getAttributeAsFloat("targetOffsetZ"));
				m_selection[1]->m_UserData->setAttribute("targetHeightOff", m_selection[0]->m_UserData->getAttributeAsFloat("targetHeightOff"));
			}			
		}
		else
		{
			wchar_t buf[256];
			wsprintf(buf,L"Copy camera control point %d to %d?",m_selection[0]->m_SceneNode->getID(), m_selection[1]->m_SceneNode->getID());
			
			IGUIElement* box = g->guienv->addMessageBox(L"Confirm!",buf, true, EMBF_YES | EMBF_NO, 0, MSG_BOX_CONFIRM_COPY_CAMERA );
			m_ckb_cpycam_pos = g->guienv->addCheckBox(true, irr::core::rect<s32>(400,30,460,50),box,-1,L"pos");
			m_ckb_cpycam_cam = g->guienv->addCheckBox(true, irr::core::rect<s32>(400,52,460,72),box,-1,L"camera");
			m_ckb_cpycam_target = g->guienv->addCheckBox(true, irr::core::rect<s32>(400,74,460,94),box,-1,L"target");
		}

		return;
		
	}
	while(false);

	stringw strError = L"Please select two CamCtrlPoint object first!";		
	g->guienv->addMessageBox(L"Error!", strError.c_str(), true);
}

void CLevelEditor::CorrectSelectedCameraArea()
{
	int error = 1;

	do
	{
		if (m_selection.size()!=1)
		{			
			break;
		}		

		CSceneObject* pObj = m_selection[0];
		if(pObj->m_type == E_OBJ_CAMERA_AREA)
		{
		}
		else if(pObj->m_type == E_OBJ_CAM_CTRL_POINT)
		{
			int caID = pObj->m_UserData->getAttributeAsInt("!^Owner^CameraArea");
			if(caID<0)
			{
				error = 2;
				break;
			}

			pObj = getSceneObjectFromID(caID);
			if(pObj==0)
			{
				error = 2;
				break;
			}
		}
		else
		{			
			break;
		}

		//get 4 ctrl points

		int id1 = pObj->m_UserData->getAttributeAsInt("^Point1^CamCtrlPoint");
		int id2 = pObj->m_UserData->getAttributeAsInt("^Point2^CamCtrlPoint");
		int id3 = pObj->m_UserData->getAttributeAsInt("^Point3^CamCtrlPoint");
		int id4 = pObj->m_UserData->getAttributeAsInt("^Point4^CamCtrlPoint");
			
		if(id1>=0 && id2>=0 && id3>=0 && id4>=0)
		{
			CSceneObject* obj1= getSceneObjectFromID(id1);
			CSceneObject* obj2= getSceneObjectFromID(id2);
			CSceneObject* obj3= getSceneObjectFromID(id3);
			CSceneObject* obj4= getSceneObjectFromID(id4);
	
			if(obj1!=0 && obj2!=0 && obj3!=0 && obj4!=0)
			{
				//make 4 ctrl points and the CameraArea object on one plane, the plane is defined by first 3 points.
				
				//define the plane
				irr::core::vector3df pos1 = obj1->m_SceneNode->getPosition();
				irr::core::vector3df pos2 = obj2->m_SceneNode->getPosition();
				irr::core::vector3df pos3 = obj3->m_SceneNode->getPosition();
				irr::core::vector3df pos4 = obj4->m_SceneNode->getPosition();
				irr::core::plane3df plane(pos1,pos2,pos3);
				
				//make the fourth point on the plane
				if(plane.classifyPointRelation(pos4)!=ISREL3D_PLANAR)
				{
					irr::core::vector3df newPos;
					if(!plane.getIntersectionWithLine(pos4,plane.Normal,newPos))
					{
						error = 4;//should never occur
						break;
					}
					obj4->m_SceneNode->setPosition(newPos);
					obj4->m_SceneNode->OnAnimate(0);
				}
				

				//make the CameraArea on the plane
				//irr::core::vector3df posCAObj = pObj->m_SceneNode->getAbsolutePosition();
				//if(plane.classifyPointRelation(posCAObj)!=ISREL3D_PLANAR)
				//{
				//	irr::core::vector3df newPos;
				//	if(!plane.getIntersectionWithLine(posCAObj,plane.Normal,newPos))
				//	{
				//		error = 4;//should never occur
				//		break;
				//	}
				//	pObj->m_SceneNode->setPosition(newPos);
				//	pObj->m_SceneNode->OnAnimate(0);		
				//}
				//make the CameraArea on the center of the area
				irr::core::vector3df newPos = (pos1+pos2+pos3+pos4)/4;
				pObj->m_SceneNode->setPosition(newPos);
				pObj->m_SceneNode->OnAnimate(0);


				//make four control points target limit on the plane
				//CSceneObject* ccps[] = {obj1, obj2, obj3, obj4};
				//for(int ccpi=0; ccpi<4; ccpi++)
				//{
				//	irr::core::vector3df tarOff;
				//	tarOff.X = ccps[ccpi]->m_UserData->getAttributeAsFloat("targetOffsetX");
				//	tarOff.Y = ccps[ccpi]->m_UserData->getAttributeAsFloat("targetOffsetY");
				//	tarOff.Z = ccps[ccpi]->m_UserData->getAttributeAsFloat("targetOffsetZ");

				//	irr::core::vector3df limitPos = ccps[ccpi]->m_SceneNode->getPosition() + tarOff;					

				//	if(plane.classifyPointRelation(limitPos)!=ISREL3D_PLANAR)
				//	{
				//		irr::core::vector3df newPos;
				//		if(!plane.getIntersectionWithLine(limitPos,plane.Normal,newPos))
				//		{
				//			error = 4;//should never occur
				//			break;
				//		}

				//		tarOff = newPos - ccps[ccpi]->m_SceneNode->getPosition();
				//		ccps[ccpi]->m_UserData->setAttribute("targetOffsetX", tarOff.X);
				//		ccps[ccpi]->m_UserData->setAttribute("targetOffsetY", tarOff.Y);
				//		ccps[ccpi]->m_UserData->setAttribute("targetOffsetZ", tarOff.Z);
				//	}
				//}

				//set new normal attribute for CameraArea
				pObj->m_UserData->setAttribute("normal",-plane.Normal);//Because irr's crossProduct is inveserd if use right hand
			}
			else
			{
				error = 3;
				break;
			}
		}
		else
		{
			error = 3;
			break;
		}

		//g->guienv->addMessageBox(L"Done!", L"Work is done!", true);

		return;
	}while(false);

	stringw strError = L"";
	
	if(error==1)
		strError += L"Please select ONE CameraArea object or ONE CamCtrlPoint object first!";
	else if(error==2)
		strError += L"The selected CamCtrlPoint does not have a owner CameraArea!";
	else if(error==3)
		strError += L"The selected CameraArea does not have FOUR CamCtrlPoint objects!";
	else if(error==4)
		strError += L"Math error! The point can not projected to the plane!";

	g->guienv->addMessageBox(L"Error!", strError.c_str(), true);	
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
ISceneNode* CLevelEditor::createCameraDirCtl(CGameObject* objTemplate)
{
	ISceneNode* node = 0;

	f32 size = objTemplate->m_Attributes->getAttributeAsFloat("Size");
	f32 angle = objTemplate->m_Attributes->getAttributeAsFloat("Angle");
	
	node = g->sceneManager->addMeshSceneNode( 0 , GetParentFromSelection(objTemplate->m_Attributes->getAttributeAsString("!GameType")) , -1 , vector3df(0,0,0) , vector3df(0,0,0) , vector3df(1,1,1) , true );	
	IMesh* mesh = createTriPrismMeshWithParams(size, angle);
	((IMeshSceneNode*)node)->setMesh(mesh);
	mesh->drop();

	return node;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
ISceneNode* CLevelEditor::createEmptySceneNode(CGameObject* objTemplate)
{
	ISceneNode* node = 0;

	node = g->sceneManager->addEmptySceneNode( GetParentFromSelection(objTemplate->m_Attributes->getAttributeAsString("!GameType")));
	
	return node;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::SetPositionInFrontOfTheCamera(ISceneNode* node)
{
	if (g->sceneManager->getActiveCamera())
	{
		vector3df targetPos = g->sceneManager->getActiveCamera()->getTarget();
		ISceneNode* pParent = node->getParent();
		
		if (pParent)
		{
			matrix4 matAbsTransform = node->getAbsoluteTransformation();
			matAbsTransform.setTranslation(targetPos);
			matrix4 matParentAbsTransform = pParent->getAbsoluteTransformation();
			matParentAbsTransform.makeInverse();
			node->setRelativeTransformation(matParentAbsTransform * matAbsTransform);
		}
		else
		{
			node->setPosition(targetPos);
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::editObject(bool axisX, bool axisY, bool axisZ, position2di mousePos)
{
	int editType = ui->getEditAction();
	int mouseMoveX = m_SelectedMousePos.X - mousePos.X;
	int mouseMoveY = m_SelectedMousePos.Y - mousePos.Y;

	//int mouseMove = std::max( abs(mouseMoveX) , abs(mouseMoveY) );
	switch (editType)
	{
		case UI_EDIT_ACTION_MOVE:
		{
			vector3df sPos = m_SelectedNode->getPosition();
			if (axisX)				
				sPos.X = m_SelectedNodePos.X + mouseMoveX;
			if (axisY)
				sPos.Y = m_SelectedNodePos.Y + mouseMoveY;
			if (axisZ)
				sPos.Z = m_SelectedNodePos.Z + mouseMoveY;
			m_SelectedNode->setPosition(sPos);
		}
			break;

		case UI_EDIT_ACTION_ROTATE:
		{		
			vector3df sRotAxis;
			vector3df sRot;

			if (axisX)
				sRotAxis += vector3df((f32)mouseMoveX * PI/180, 0.0, 0.0);
			if (axisY)
				sRotAxis += vector3df(0.0, (f32)mouseMoveY * PI/180, 0.0);
			if (axisZ)
				sRotAxis += vector3df(0.0, 0.0, (f32)mouseMoveY * PI/180);
			
			quaternion qq(sRotAxis);
			
			//m_SelectedNode->setRotation(m_SelectedNode->getRotation() * qq);
		}
		break;

		case UI_EDIT_ACTION_SCALE:
		{
			vector3df sScale = m_SelectedNode->getScale();
			if (axisX)
				sScale.X = m_SelectedNodeScale.X + (f32)mouseMoveX / 100;
			if (axisY)
				sScale.Y = m_SelectedNodeScale.Y + (f32)mouseMoveY / 100;
			if (axisZ)
				sScale.Z = m_SelectedNodeScale.Z + (f32)mouseMoveY / 100;
			m_SelectedNode->setScale(sScale);
		}
		break;
	}
	
	ui->updateProperties();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::updateControls ()
{
	m_updateControls = true;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::doUpdateControls ()
{
	if (!m_updateControls)
		return;

	m_updateControls = false;

	g->eventReceiver->RemoveAllControls();
	if (m_selection.size() > 0)
	{
		vector3df e1(1,0,0);
		vector3df e2(0,1,0);
		vector3df e3(0,0,1);
		vector3df e4(1,1,1);

		ISceneNode* node = m_selection[0]->m_SceneNode;
		array<ISceneNode*> nodes;
		for (u32 i = 0; i < m_selection.size(); ++i)
			nodes.push_back(m_selection[i]->m_SceneNode);

		switch (ui->getEditAction())
		{
		case UI_EDIT_ACTION_ROTATE:
			g->eventReceiver->AddControl(new CRotationControl(nodes, e1, e3, SColor(255,0,127,0), SColor(255,0,255,0)));
			g->eventReceiver->AddControl(new CRotationControl(nodes, e1, e2, SColor(255,0,0,127), SColor(255,0,0,255)));
			g->eventReceiver->AddControl(new CRotationControl(nodes, e2, e3, SColor(255,127,0,0), SColor(255,255,0,0)));
			break;

		case UI_EDIT_ACTION_ROTATE_LOCAL:
		{
			if (m_selection.size() > 1) return;

			quaternion q = node->getRotation();
			q.makeInverse();
			g->eventReceiver->AddControl(new CRotationControl(nodes, q*e1, q*e3, SColor(255,0,127,0), SColor(255,0,255,0)));
			g->eventReceiver->AddControl(new CRotationControl(nodes, q*e1, q*e2, SColor(255,0,0,127), SColor(255,0,0,255)));
			g->eventReceiver->AddControl(new CRotationControl(nodes, q*e2, q*e3, SColor(255,127,0,0), SColor(255,255,0,0)));
			break;
		}

		case UI_EDIT_ACTION_MOVE:
		{
			g->eventReceiver->AddControl(new CPlaneControl(nodes, e1, e3, SColor(255,0,127,0), SColor(255,0,255,0)));
			g->eventReceiver->AddControl(new CPlaneControl(nodes, e1, e2, SColor(255,0,0,127), SColor(255,0,0,255)));
			g->eventReceiver->AddControl(new CPlaneControl(nodes, e2, e3, SColor(255,127,0,0), SColor(255,255,0,0)));
		
			g->eventReceiver->AddControl(new CAxisControl(nodes, e1, SColor(255,127,0,0), SColor(255,255,0,0)));
			g->eventReceiver->AddControl(new CAxisControl(nodes, e2, SColor(255,0,127,0), SColor(255,0,255,0)));
			g->eventReceiver->AddControl(new CAxisControl(nodes, e3, SColor(255,0,0,127), SColor(255,0,0,255)));
		}

			break;

		case UI_EDIT_ACTION_MOVE_LOCAL:
		{
			if (m_selection.size() > 1) return;

			quaternion q = node->getRotation();
			q.makeInverse();
			g->eventReceiver->AddControl(new CPlaneControl(nodes, q*e1, q*e3, SColor(255,0,127,0), SColor(255,0,255,0)));
			g->eventReceiver->AddControl(new CPlaneControl(nodes, q*e1, q*e2, SColor(255,0,0,127), SColor(255,0,0,255)));
			g->eventReceiver->AddControl(new CPlaneControl(nodes, q*e2, q*e3, SColor(255,127,0,0), SColor(255,255,0,0)));
			g->eventReceiver->AddControl(new CAxisControl(nodes, q*e1, SColor(255,127,0,0), SColor(255,255,0,0)));
			g->eventReceiver->AddControl(new CAxisControl(nodes, q*e2, SColor(255,0,127,0), SColor(255,0,255,0)));
			g->eventReceiver->AddControl(new CAxisControl(nodes, q*e3, SColor(255,0,0,127), SColor(255,0,0,255)));
			break;
		}

		case UI_EDIT_ACTION_SCALE:
			//g->eventReceiver->AddControl(new CPlaneControl(nodes, e1, e3, SColor(255,0,127,0), SColor(255,0,255,0)));
			//g->eventReceiver->AddControl(new CPlaneControl(nodes, e1, e2, SColor(255,0,0,127), SColor(255,0,0,255)));
			//g->eventReceiver->AddControl(new CPlaneControl(nodes, e2, e3, SColor(255,127,0,0), SColor(255,255,0,0)));

			g->eventReceiver->AddControl(new CAxisControl(nodes, e4, SColor(255,255,240,240), SColor(255,255,255,255)));
			g->eventReceiver->AddControl(new CAxisControl(nodes, e1, SColor(255,127,0,0), SColor(255,255,0,0)));
			g->eventReceiver->AddControl(new CAxisControl(nodes, e2, SColor(255,0,127,0), SColor(255,0,255,0)));
			g->eventReceiver->AddControl(new CAxisControl(nodes, e3, SColor(255,0,0,127), SColor(255,0,0,255)));

			break;

		case UI_EDIT_ACTION_MODIFY:
			{
				if (m_selection.size() > 1) return; //ms modify one trigger at the time 
				if ( m_selection[0]->m_UserData->getAttributeAsString("!GameType") != stringc("Trigger") &&
					m_selection[0]->m_UserData->getAttributeAsString("!GameType") != stringc("TriggerSound") &&
					m_selection[0]->m_UserData->getAttributeAsString("!GameType") != stringc("Cover") &&
					m_selection[0]->m_UserData->getAttributeAsString("!GameType") != stringc("EffectDamage") &&
					m_selection[0]->m_UserData->getAttributeAsString("!GameType") != stringc("DropArea") &&
					m_selection[0]->m_UserData->getAttributeAsString("!GameType") != stringc("TriggerRestore") &&
					m_selection[0]->m_UserData->getAttributeAsString("!GameType") != stringc("CheckPoint")
					)
					return ;// modify only triggers
				g->eventReceiver->AddControl(new CFaceControl(m_selection[0]->m_SceneNode, e1 , m_selection[0]->m_UserData->getAttributeAsVector3d("Sizes") , SColor(255,127,0,0), SColor(255,255,0,0)));
				g->eventReceiver->AddControl(new CFaceControl(m_selection[0]->m_SceneNode, e2 , m_selection[0]->m_UserData->getAttributeAsVector3d("Sizes") , SColor(255,0,127,0), SColor(255,0,255,0)));
				g->eventReceiver->AddControl(new CFaceControl(m_selection[0]->m_SceneNode, e3 , m_selection[0]->m_UserData->getAttributeAsVector3d("Sizes") , SColor(255,0,0,127), SColor(255,0,0,255)));
			}
			break;
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::setSelectedNode(ISceneNode* node)
{
	if(m_SelectedNode == node)
		return;

	if(node)
	{
		if(ui->m_sceneGraphTree->FindNode(node->getID())->Locked)
			return;

		if (ui->m_CinematicEditor.m_Active)
		{
			ui->m_CinematicEditor.SetThreadObject(node->getID());
		}
	}
	
	if (ui->m_linkChangedProp != NULL)
	{		
		stringw filter = GetFilterFromName(ui->m_linkChangedProp->m_Name);
		if (node)
		{
			CSceneObject* obj = getSceneObjectFromID(node->getID());
			if (obj)
			{
				if (filter == "" || ( obj->m_UserData->getAttributeAsStringW("!GameType") == filter ))
				{
					AddCommand(new CSetIntAttributeCommand(m_SelectedNode->getID(),
							stringc(ui->m_linkChangedProp->m_Name.c_str()), node->getID()));					
				}
			}
		}

		((IGUIButton*)ui->m_linkChangedProp->m_GUIElementButton)->setPressed(false);
		ui->m_linkChangedProp = NULL;
	}

	m_SelectedNode = node;
	m_selection.clear();
	updateControls();

	if (!node)
	{
		ui->clearPropertiesWindow();
		ui->m_sceneGraphTree->SetSelected(0);
		//m_HasActiveZone = false;	
	}
	else
	{		
		ui->createSelectedObjectProperties();
		ui->m_sceneGraphTree->SetSelected(ui->m_sceneGraphTree->FindNode(node->getID()));
		m_selection.push_back(getSceneObjectFromID(node->getID()));		
		if (ui->m_CinematicEditor.m_Active)
			ui->m_CinematicEditor.setObjectID(m_SelectedNode->getID());

	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
CSceneObject* CLevelEditor::getSceneObjectFromID(s32 id)
{
	CSceneObject* sceneObject = 0;

	for (u32 i = 0; i < m_SceneObjects.size(); i ++)
		if (m_SceneObjects[i]->m_SceneNode->getID() == id)
		{
			sceneObject = m_SceneObjects[i];
			break;
		}
	
	return sceneObject;
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------

void  CLevelEditor::GetChildren(const s32 ID  , const s32 level , TreeList& list )
{
	TreeNode* node = ui->m_sceneGraphTree->FindNode( ID );

	ObjectsList* objList = 0;
	TreeListIter iter = list.find(level);
	
	if (iter.atEnd())
	{
		list[level] = new irr::core::array<CSceneObject*>;
	}

	ObjectsList* obj = list[level];
	
	for (TreeNode* child = node->Child; child; child = child->Sibling)
	{		
		obj->push_back(child->SceneObject);
		GetChildren(child->SceneObject->m_SceneNode->getID() , level + 1 ,  list ); 
	}
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
array<stringw> CLevelEditor::getGameListArray(stringw name)
{
	if (name.find(L"MAIN_STRINGID") == 0)
	{
		return m_stringsList.Items;
	}	

	if (name.find("SkillID") != -1)
	{
		return m_skillList.Items;
	}

	stringw nameFlag = name;
	if( name.find(L"LEVEL_STRINGID") == 0)
	{
		//s32 pos = m_SceneFileName.findFirst(L'.');
		stringw nameLevel;
		//if( pos != -1 )
		//{
		//	nameLevel.append( m_SceneFileName.subString(0, pos ).c_str() );
		//	nameLevel += L"_STRINGID";
		//}
		nameLevel.append( GetMappingLevelNameByIrrName(0, m_SceneFileName.c_str() ) );
		nameLevel += L"_STRINGID";
		nameFlag = nameLevel;
	}

	for (u32 i = 0; i < m_GameLists.size(); i ++)
		if (m_GameLists[i].Name == nameFlag)
			return m_GameLists[i].Items;
	return 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::cloneSelectedNode()
{
	CSceneObject* node = cloneNode(m_SelectedNode);
	//AddInsertCommand(node);
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
CSceneObject* CLevelEditor::cloneGameObject(CSceneObject *pNode)
{
	CSceneObject* newSceneObject = NULL;

	stringc objType = pNode->m_UserData->getAttributeAsString("!GameType");
	s32 index = getGameObjectIndexFromGameType(objType);

	newSceneObject = createGameObject(index , -1);
	GX_ASSERT(newSceneObject);

	s32 id = newSceneObject->m_SceneNode->getID();
	
	copyAttributes(newSceneObject->m_UserData, pNode->m_UserData, -1, true);

	newSceneObject->InitAttributes();

	IAttributes* attr = g->device->getFileSystem()->createEmptyAttributes();
	pNode->m_SceneNode->serializeAttributes(attr);
	newSceneObject->m_SceneNode->deserializeAttributes(attr);
	attr->drop();

	newSceneObject->m_SceneNode->setPosition(pNode->m_SceneNode->getPosition());
	newSceneObject->m_SceneNode->setID(id);	
	newSceneObject->ProcessAttributes();

	TreeNode* pTreeNode = ui->m_sceneGraphTree->FindNode(newSceneObject->m_SceneNode->getID());
	
	pTreeNode->Checked = newSceneObject->m_SceneNode->isVisible();
	pTreeNode->Text = stringw(newSceneObject->m_SceneNode->getID()) + " - " + newSceneObject->m_UserData->getAttributeAsStringW("Name");
	pTreeNode->LowerText = pTreeNode->Text;
	pTreeNode->LowerText.make_lower();
	
	if(!newSceneObject->m_SceneNode->isVisible())								
		ui->setSceneNodeVisible(newSceneObject->m_SceneNode->getID(), newSceneObject->m_SceneNode->isVisible());

	if (newSceneObject->m_UserData->getAttributeAsString("!GameType") == "Cinematic")
	{
		CopyFile(pNode->m_UserData->getAttributeAsStringW("!ScriptFile").c_str(),
			newSceneObject->m_UserData->getAttributeAsStringW("!ScriptFile").c_str(), false);
	}

	return newSceneObject;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
CSceneObject* CLevelEditor::cloneNode(ISceneNode *pNode)
{
	if (!pNode)
		return NULL;
	
	CSceneObject* selectedObject = getSceneObjectFromID(pNode->getID());
	
	TreeList newList;		
	ObjectsList* lst = new irr::core::array<CSceneObject*>;

	lst->push_back(selectedObject);
	newList[0] = lst;

	GetChildren(selectedObject->m_SceneNode->getID() , 1 , newList );	
	
	TreeNode* _pTreeNode = ui->m_sceneGraphTree->FindNode(pNode->getID());
	if (_pTreeNode)
	{
		if (_pTreeNode->Parent && _pTreeNode->Parent->SceneObject)
		{
			setSelectedNode(_pTreeNode->Parent->SceneObject->m_SceneNode);
		}
		else
		{
			setSelectedNode(NULL);
		}
	}		
		
	CSceneObject* pObj = NULL , * newSceneObject = NULL;
	// clone for every object 
	for (int i = 0 ; i < newList.size() ; i ++ )
	{	
		ObjectsList* lst = newList[i];
		
		for ( int j = 0 ; j < lst->size() ; j++)
		{
			pObj = cloneGameObject( (*lst)[j] );
		}
		
		setSelectedNode(pObj->m_SceneNode);
		//keep a pointer to our first object 
		if (i == 0)
		{
			newSceneObject = pObj;
		}
	}

	return newSceneObject;
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::newScene()
{
	m_SceneFileName = "";

	m_SelectedNode = 0;
	m_LastFocusedNode = 0;
	m_bModified = false;
	
	g->sceneManager->clear();
	ReAddEffectsToScene();

	for (u32 i = 0; i < m_SceneObjects.size(); i ++)
		if (m_SceneObjects[i])
		{
			delete m_SceneObjects[i];
			m_SceneObjects[i] = 0;
		}
	m_SceneObjects.clear();
	ui->m_sceneGraphTree->Clear();
	g->initScene();

	//g->camera[MAYA_CAMERA]->setFarValue(m_mayaCameraFar);	

	m_selection.clear();

	m_lastUniqueId = 0;

	for (u32 i = 0; i < m_HistoryCommands.size(); ++i)
	{
		m_HistoryCommands[i]->drop();
	}
	m_HistoryCommands.clear();
	m_LastCommand = 0;
	ui->m_HistoryList->clear();
	ui->m_SceneGraphPropertiesVisibleList->clear();
	ui->m_SceneGraphPropertiesInvisibleList->clear();
	ui->m_SceneGraphPropertiesLockedList->clear();
	m_nHistoryCommands = 0;
	AddCommand(new CEmptyCommand);

}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::drawObjectManipulationControls ()
{
	if (!m_SelectedNode)
		return;

	g->driver->clearZBuffer();
	g->eventReceiver->DrawControls();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::toggleToSelection (ISceneNode* node)
{
	if (m_selection.size() == 0)
	{
		setSelectedNode(node);
	}
	else
	{
		CSceneObject* obj = getSceneObjectFromID(node->getID());
		for (u32 i = 0; i < m_selection.size(); ++i)
			if (m_selection[i] == obj)
			{
				m_selection.erase(i);
				if (m_selection.size() == 1)
				{
					setSelectedNode(m_selection[0]->m_SceneNode);
				}
				else if (m_selection.size() == 0)
				{
					setSelectedNode(0);
				}
				updateControls();
				ui->m_sceneGraphTree->updateSelected();
				return;
			}

		TreeNode* treeNode = ui->m_sceneGraphTree->FindNode(obj->m_SceneNode->getID());
		if(treeNode && !treeNode->Locked)			
			m_selection.push_back(obj);

		ui->m_sceneGraphTree->updateSelected();
	}
	updateControls();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::drawSelectedNode (ISceneNode *pNode)
{
	if (!pNode->isVisible())
		return;

	pNode->OnRegisterSceneNode();
	pNode->updateAbsolutePosition();

	array<SMaterial> materials;
	for (u32 j = 0; j < pNode->getMaterialCount(); ++j)
	{
		SMaterial& mat = pNode->getMaterial(j);
		materials.push_back(mat);
		mat.DiffuseColor = SColor(100, 0, 255, 0);
		mat.setFlag(EMF_LIGHTING, false);
		mat.setFlag(EMF_WIREFRAME, true);
		mat.Thickness = 1;
		mat.setTexture(0, 0);
		mat.MaterialType = EMT_SOLID;
	}
	
	//if (pNode->getType() != ESNT_COLLADA_CAMERA && pNode->getType() != ESNT_SKY_BOX)//dai_yx
	//{
	//	bool bDraw = true;
	//	if (m_bLinkRoomMode)
	//	{
	//		bDraw = false;

	//		stringc nodeName = pNode->getName();

	//		for (int i=0; i < MAX_ROOM_LINKS; i++)
	//		{
	//			stringc name("LinkNode");
	//			name += i;

	//			if (name == nodeName)
	//			{
	//				bDraw = true;
	//				break;
	//			}
	//		}
	//	}

	//	if (bDraw) 
	//	{
	//		for (u32 j = 0; j < pNode->getMaterialCount(); ++j)
	//		{
	//			pNode->render((void*)(j+1));
	//		}
	//	}
	//}


	for (u32 j = 0; j < pNode->getMaterialCount(); ++j)
	{
		pNode->getMaterial(j) = materials[j];
	}

	core::list<ISceneNode*>::ConstIterator it = pNode->getChildren().begin();
	for (; it != pNode->getChildren().end(); ++it)
	{
		drawSelectedNode((*it));
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::drawSelectedObjects ()
{
	for (u32 i = 0; i < m_selection.size(); ++i)
	{
		CSceneObject* obj = m_selection[i];
		if (obj->m_UserData->getAttributeAsString("!GameType") != stringc("Effect"))
		{			
			drawSelectedNode(obj->m_SceneNode);
		}
		else if (obj->m_UserData->getAttributeAsString("!GameType") != stringc("EffectDemage"))
		{			
			drawSelectedNode(obj->m_SceneNode);
		}
	}
	//for (u32 i = 0; i < m_selectedIndices.size(); ++i)
	//{
	//	int id = m_onScreenIds[m_selectedIndices[i]];
	//	CSceneObject* obj = getSceneObjectFromID(id);
	//	array<SMaterial> materials;
	//	for (u32 j = 0; j < obj->m_SceneNode->getMaterialCount(); ++j)
	//	{
	//		SMaterial& mat = obj->m_SceneNode->getMaterial(j);
	//		materials.push_back(mat);
	//		mat.EmissiveColor = SColor(100, 255, 255, 0);
	//		mat.Lighting = true;
	//		mat.Wireframe = true;
	//		mat.Thickness = 1;
	//		mat.setTexture(0, 0);
	//		mat.MaterialType = EMT_SOLID;
	//	}
	//	obj->m_SceneNode->render();
	//	for (u32 j = 0; j < obj->m_SceneNode->getMaterialCount(); ++j)
	//	{
	//		obj->m_SceneNode->getMaterial(j) = materials[j];
	//	}
	//}

	for (u32 i = 0; i < m_selection.size(); ++i)
	{
		CSceneObject* obj = m_selection[i];

		SMaterial Material;

		Material.setFlag(EMF_WIREFRAME, false);
		Material.setFlag(EMF_LIGHTING, false);

		g->driver->setMaterial(Material);
		g->driver->setTransform(video::ETS_WORLD, core::matrix4());

		//obj->m_SceneNode->OnAnimate(50.0f);

		aabbox3df box;
		GetAbsoluteBoundingBox(obj->m_SceneNode, box);

		g->driver->draw3DBox(box, SColor(255, 255, 0, 0));
	}

	if ( m_selection.size() == 2)
	{
		g->driver->draw3DLine(m_selection[0]->m_SceneNode->getAbsolutePosition() , 
			m_selection[1]->m_SceneNode->getAbsolutePosition() , 
			SColor( 255 ,  0 , 255 , 0 ) ); 

		vector3df dist = m_selection[0]->m_SceneNode->getAbsolutePosition() - m_selection[1]->m_SceneNode->getAbsolutePosition();
		
		stringw dis = L" ( ";		
		dis += dist.getLength();
		dis += " ) ";
		
		vector2df screenPos;
		if (!project3DTo2D(m_selection[1]->m_SceneNode->getAbsolutePosition() + dist / 2, &screenPos)) return;

		int x = (int)screenPos.X;
		int y = (int)screenPos.Y;
		
		position2di pos(x , y);
		position2di size(100 , 100);

		rect<s32> rc(pos, size);

//		g->driver->beginScene2D();
		g->guienv->getSkin()->getFont()->draw(dis.c_str(), rc, SColor(255, 255, 255, 255));
//		g->driver->endScene2D();
		
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::GetAbsoluteBoundingBox(ISceneNode* pNode, aabbox3df& box)
{
	//DEBUG_OUT("--------------------------\n");
	box.reset(0, 0, 0);
	GetColladaBoundingBox(pNode, box, "---");
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::GetColladaBoundingBox(ISceneNode* pNode, aabbox3df& box, stringc dummy)//dai_yx
{
	//stringc name = pNode->getName();

	//if (pNode->getType() == ESNT_COLLADA_NODE && name != stringc("door_l") && name != stringc("door_1_recover_max"))
	//{
	//	return;
	//}

	//DEBUG_OUT((dummy + "node type %d nodeName %s\n").c_str(), pNode->getType(), pNode->getName());

	//bool visible =  pNode->isVisible();
	//if(visible && pNode->getParent()!=0)
	//{
	//	visible = pNode->getParent()->isVisible();			
	//}

	//if (visible &&
	//		(pNode->getType() == ESNT_COLLADA_MESH ||
	//		pNode->getType() == ESNT_COLLADA_SKIN_MESH ||
	//		pNode->getType() == ESNT_COLLADA_MODULAR_SKIN_MESH)
	//	)
	//{		
	//	//DEBUG_OUT((dummy + "node type %d nodeName %s\n").c_str(), pNode->getType(), pNode->getName());

	//	irr::scene::CColladaMesh* pMesh = (irr::scene::CColladaMesh*)((CColladaMeshSceneNode*)pNode)->getMesh();
	//	aabbox3df _box = pNode->getBoundingBox();

	//	if (pMesh->getType() != irr::scene::IColladaMesh::ET_SKINNED_MESH &&
	//		pMesh->getType() != irr::scene::IColladaMesh::ET_MODULAR_SKINNED_MESH)
	//	{
	//		matrix4 mat = pNode->getAbsoluteTransformation();
	//		//mat.transformVect(_box.MinEdge);
	//		//mat.transformVect(_box.MaxEdge);
	//		mat.transformBoxEx(_box);
	//	}

	//	if (box.isEmpty())
	//	{
	//		box = _box;
	//	}
	//	else
	//	{
	//		box.addInternalBox(_box);
	//	}
	//}

	//const irr::core::list<irr::scene::ISceneNode*>& list = pNode->getChildren();
	//irr::core::list<irr::scene::ISceneNode*>::ConstIterator it;
	//
	//for(it = list.begin(); it != list.end(); it++)
	//{
	//	GetColladaBoundingBox((*it), box, dummy + "---");
	//}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool CLevelEditor::RayCollision(const vector3df &inRayPoint, 
							const vector3df &inRayDirection, 
									vector3df &outCollisionPoint, bool bCulling)
{
	core::triangle3df triangle;
	core::line3df ray(inRayPoint, inRayPoint + inRayDirection);

	//bool bCollisionFound = ((CFPSSceneCollisionManager*)g->sceneManager->getSceneCollisionManager())->getCollisionPoint(
	//		ray, m_pCollisionTriSelector, outCollisionPoint, triangle, bCulling);
	bool bCollisionFound = m_physicalWorld->CollideRayWithWorld(inRayPoint , inRayPoint + inRayDirection , outCollisionPoint , triangle);

	m_collTriangle = triangle;

	return bCollisionFound;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
IMesh* CLevelEditor::createMesh()
{
	SMesh* Mesh = new SMesh();

	const u16 u[36] = {   0,2,1,   0,3,2,   1,5,4,   1,2,5,   4,6,7,   4,5,6, 
            7,3,0,   7,6,3,   9,5,2,   9,8,5,   0,11,10,   0,10,7};

	SMeshBuffer* buf = new SMeshBuffer();
	Mesh->addMeshBuffer(buf);
	buf->Indices.set_used(36);
	for (u32 i=0; i<36; ++i)
		buf->Indices[i] = u[i];
	buf->drop();


	video::SColor clr(100,255,0,0);

	buf = (SMeshBuffer*)Mesh->getMeshBuffer(0);

	buf->Vertices.reallocate(12);
	// Start setting vertices from index 0 to deal with this method being called multiple times.
	buf->Vertices.set_used(0);
	buf->Vertices.push_back(video::S3DVertex(0,0,0, -1,-1,-1, clr, 0, 1));
	buf->Vertices.push_back(video::S3DVertex(1,0,0,  1,-1,-1, clr, 1, 1));
	buf->Vertices.push_back(video::S3DVertex(1,1,0,  1, 1,-1, clr, 1, 0));
	buf->Vertices.push_back(video::S3DVertex(0,1,0, -1, 1,-1, clr, 0, 0));
	buf->Vertices.push_back(video::S3DVertex(1,0,1,  1,-1, 1, clr, 0, 1));
	buf->Vertices.push_back(video::S3DVertex(1,1,1,  1, 1, 1, clr, 0, 0));
	buf->Vertices.push_back(video::S3DVertex(0,1,1, -1, 1, 1, clr, 1, 0));
	buf->Vertices.push_back(video::S3DVertex(0,0,1, -1,-1, 1, clr, 1, 1));
	buf->Vertices.push_back(video::S3DVertex(0,1,1, -1, 1, 1, clr, 0, 1));
	buf->Vertices.push_back(video::S3DVertex(0,1,0, -1, 1,-1, clr, 1, 1));
	buf->Vertices.push_back(video::S3DVertex(1,0,1,  1,-1, 1, clr, 1, 0));
	buf->Vertices.push_back(video::S3DVertex(1,0,0,  1,-1,-1, clr, 0, 0));	
	
	return Mesh;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
    011         111
      /6,8------/5        z
     /  |      / |        ^  y
    /   |     /  |        | /
010 3,9-------2  |        |/
    |   7- - -10,4 101     *---->x
    |  /      |  /
    |/        | /
    0------11,1/
   000       100       
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IMesh* CLevelEditor::createMeshWithSize( vector3df size)
{
	IMesh* Mesh = createMesh();

	updateMeshWithSize(Mesh , size);
		
	return Mesh;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::updateMeshWithSize( IMesh* Mesh , vector3df size )
{
	SMeshBuffer* buf = (SMeshBuffer*)Mesh->getMeshBuffer(0);
	
	buf->BoundingBox.reset(0,0,0); 
		
	buf->Vertices[0].Pos = vector3df(0,0,0) * size;
	buf->Vertices[1].Pos = vector3df(1,0,0) * size;
	buf->Vertices[2].Pos = vector3df(1,1,0) * size;
	buf->Vertices[3].Pos = vector3df(0,1,0) * size;
	buf->Vertices[4].Pos = vector3df(1,0,1) * size;
	buf->Vertices[5].Pos = vector3df(1,1,1) * size;
	buf->Vertices[6].Pos = vector3df(0,1,1) * size;
	buf->Vertices[7].Pos = vector3df(0,0,1) * size;

	vector3df m_centroid = vector3df();	
	
	for (int i = 0; i < 8; ++i)
	{
		m_centroid += buf->Vertices[i].Pos;
	}

	m_centroid /= 8;

	for (int i = 0; i < 8; ++i)
	{
		buf->Vertices[i].Pos -= m_centroid;
	}

	buf->Vertices[8].Pos = buf->Vertices[6].Pos; // ok 6
	buf->Vertices[9].Pos = buf->Vertices[3].Pos; // ok 3
	buf->Vertices[10].Pos = buf->Vertices[4].Pos; // ok 4
	buf->Vertices[11].Pos = buf->Vertices[1].Pos; // ok 1*/

	for (u32 i=0; i<12; ++i)
	{		
		buf->BoundingBox.addInternalPoint(buf->Vertices[i].Pos);			
	}

	Mesh->setBoundingBox(buf->getBoundingBox());
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
IMesh* CLevelEditor::createTriPrismMesh()
{
	SMesh* Mesh = new SMesh();

	const u16 u[24] = {0,2,1,   3,4,5,   0,1,4,		0,4,3,		1,2,5,		1,5,4,		2,0,3,		2,3,5};

	SMeshBuffer* buf = new SMeshBuffer();
	Mesh->addMeshBuffer(buf);
	buf->Indices.set_used(24);
	for (u32 i=0; i<24; ++i)
		buf->Indices[i] = u[i];
	buf->drop();

	video::SColor clr(100,0,255,0);

	buf = (SMeshBuffer*)Mesh->getMeshBuffer(0);

	buf->Vertices.reallocate(12);
	// Start setting vertices from index 0 to deal with this method being called multiple times.
	buf->Vertices.set_used(0);
	buf->Vertices.push_back(video::S3DVertex(0,0,0, -1,-1,-1, clr, 0, 0));	// 0
	buf->Vertices.push_back(video::S3DVertex(1,0,0,  1,-1,-1, clr, 1, 0));	// 1
	buf->Vertices.push_back(video::S3DVertex(0,1,0, -1, 1,-1, clr, 0, 1));	// 2
	buf->Vertices.push_back(video::S3DVertex(0,0,1, -1,-1, 1, clr, 0, 0));	// 3
	buf->Vertices.push_back(video::S3DVertex(1,0,1,  1,-1, 1, clr, 1, 0));	// 4
	buf->Vertices.push_back(video::S3DVertex(0,1,1, -1, 1, 1, clr, 0, 1));	// 5
	
	return Mesh;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

IMesh* CLevelEditor::createTriPrismMeshWithParams( f32 size, f32 angle )
{
	IMesh* Mesh = createTriPrismMesh();
	updateTriPrismMeshWithParams(Mesh , size, angle);
		
	return Mesh;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::updateTriPrismMeshWithParams( IMesh* Mesh, f32 size, f32 angle )
{
	SMeshBuffer* buf = (SMeshBuffer*)Mesh->getMeshBuffer(0);
	
	buf->BoundingBox.reset(0,0,0);

	angle *= PI / 180.0f; // converting to radians
	f32 x = size * cos(angle);
	f32 y = size * sin(angle);

	buf->Vertices[0].Pos = vector3df(0, 0, 0);
	buf->Vertices[1].Pos = vector3df(size, 0, 0);
	buf->Vertices[2].Pos = vector3df(x, y, 0);
	buf->Vertices[3].Pos = vector3df(0, 0, size/2);
	buf->Vertices[4].Pos = vector3df(size, 0, size/2);
	buf->Vertices[5].Pos = vector3df(x, y, size/2);

	vector3df m_centroid = vector3df();
	
	//for (int i = 0; i < 6; ++i)
	//{
	//	m_centroid += buf->Vertices[i].Pos;
	//}

	//m_centroid /= 6;

	//for (int i = 0; i < 6; ++i)
	//{
	//	buf->Vertices[i].Pos -= m_centroid;
	//}

	for (u32 i=0; i<6; ++i)
	{		
		buf->BoundingBox.addInternalPoint(buf->Vertices[i].Pos);			
	}

	Mesh->setBoundingBox(buf->getBoundingBox());
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::updateTrigerControls(vector3df size )
{
	g->eventReceiver->UpdateControls( size );
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
stringw CLevelEditor::GetFilterFromName(stringw name)
{
	int pos = name.findNext(L'^', 1);
	stringw filter = L"";
	if (pos != -1)
	{
		filter = name.subString(pos + 1, name.size() - pos - 1);
	}

	return filter;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::activateCamera()
{
	//if (m_SelectedNode)
	//{
	//	collada::CCameraSceneNode* node = GetColladaCameraFromVisualScene(m_SelectedNode);
	//	if (node)
	//	{	
	//		node->setUpVector( vector3df(0,0,1));
	//		g->sceneManager->setActiveCamera(node);
	//	}
	//}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
s32 CLevelEditor::getGameObjectIndexFromGameType(stringc type)
{
	for (u32 i=0; i < m_GameObjects.size(); i++)
	{
		if (type == m_GameObjects[i]->m_Attributes->getAttributeAsString("!GameType"))
		{
			return i;
		}
	}
	return -1;
}
//--------------------------------------------------------------------------------------------------
//D
//--------------------------------------------------------------------------------------------------
void CLevelEditor::update()//dai_yx
{
	//for (u32 i=0; i < m_SceneObjects.size(); i++)
	//{
	//	m_SceneObjects[i]->UpdateAnim();
	//}
	//int time = ( (CFpsSceneManager*)g->sceneManager )->getSceneTime();

	//if(m_isPlayingCinematic)
	//{
	//	PlayCinematic(time);
	//}
	//else
	//{		
	//	for (u32 i = 0; i < m_selection.size(); ++i)
	//	{
	//		CSceneObject* obj = m_selection[i];
	//		if (obj)
	//		{
	//			obj->m_SceneNode->OnAnimate( time );
	//			obj->UpdateAnim();

	//		}
	//	}
	//}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::CheckSpawnPoints(CSceneObject* object , bool value)
{
	for (u32 i=0; i < m_SceneObjects.size(); i++)
	{
		if (m_SceneObjects[i]->m_UserData->getAttributeAsString("!GameType") == stringc("SpawnPoint"))
		{
			if (m_SceneObjects[i] != object )
			{
				m_SceneObjects[i]->m_UserData->setAttribute("StartPoint" , false);
			}
			else
			{
				m_SceneObjects[i]->m_UserData->setAttribute("StartPoint" , true);
			}
		}
	}

}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::PrintRelativeTrans(ISceneNode* pNode)
{
	matrix4 mat = pNode->getRelativeTransformation();
	int type = (int)pNode->getType();
	char strType[5];
	memcpy(strType, &type, 4);
	strType[4] = '\0';
	DEBUG_OUT("%s - %s: %f, %f, %f\n", pNode->getName(), strType, mat[12], mat[13], mat[14]);

	list<ISceneNode*> children = pNode->getChildren();
	list<ISceneNode*>::Iterator iter = children.begin();
	while (iter != children.end()) 
	{
		PrintRelativeTrans((*iter));
		iter++;
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
ISceneNode*	CLevelEditor::GetParentRoom(ISceneNode* pNode)
{
	pNode = pNode->getParent();

	if (!pNode) return NULL;

	CSceneObject* pObj = getSceneObjectFromID(pNode->getID());

	if (pObj && pObj->m_UserData->getAttributeAsString("!GameType") == "Geometry")
	{
		return pObj->m_SceneNode;
	}

	return GetParentRoom(pNode);
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
ISceneNode* CLevelEditor::GetRoomRefNode(ISceneNode* pRoomNode)
{
	if (pRoomNode->getChildren().getSize() == 0) return NULL;

	core::list<ISceneNode*>::ConstIterator it = pRoomNode->getChildren().begin();

	ISceneNode *pElement = (*it);
	if( !pElement->getChildren().empty() )
	{
		return (ISceneNode*)(*((*it)->getChildren().begin()));
	}
	else
	{
		return NULL;
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::AddLinkHelperNodes(ISceneNode* pRoot)
{
	for (int i=0; i < MAX_ROOM_LINKS; i++)
	{
		stringc name("LinkNode");
		name += i;
		ISceneNode *pNode = g->sceneManager->getSceneNodeFromName(name.c_str(), pRoot);

		if (pNode)
		{
			ISceneNode *pLinkNode = g->sceneManager->addCubeSceneNode();
			pLinkNode->setVisible(true);

			SMaterial& mat = pLinkNode->getMaterial(0);
			mat.EmissiveColor = SColor(100, 0, 255, 0);
			mat.setFlag(EMF_LIGHTING, true);
			mat.setFlag(EMF_WIREFRAME, true);
			mat.Thickness = 1;
			mat.setTexture(0, 0);
			mat.MaterialType = EMT_SOLID;

			pLinkNode->setScale(vector3df(20.f, 20.f, 20.f));

			pNode->addChild(pLinkNode);

			//ISceneNode *pLinkNode1 = g->sceneManager->addCubeSceneNode();
			//pLinkNode1->setPosition(vector3df(0, 100, 0));

			//pLinkNode1->setScale(vector3df(20.f, 20.f, 20.f));

			//pNode->addChild(pLinkNode1);
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
ISceneNode* CLevelEditor::GetRoomFromHelper(ISceneNode *pHelper)
{
	ISceneNode *pNode = pHelper;
	while (pNode && pNode->getID() < 0)
	{
		pNode = pNode->getParent();
	}

	return pNode;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::ShowRoomHelpers(ISceneNode* pRoom, bool bShow)
{
	core::list<ISceneNode*>::ConstIterator it = pRoom->getChildren().begin();
	for (; it != pRoom->getChildren().end(); ++it)
	{
		for (int i=0; i < MAX_ROOM_LINKS; i++)
		{
			stringc name("LinkNode");
			name += i;

			if (name == (*it)->getName())
			{
				(*it)->setVisible(bShow);
			}
		}
		
		ShowRoomHelpers((*it), bShow);
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::LinkRoomFromTo(ISceneNode *pLinkFrom, short linkFromIndex, ISceneNode *pLinkTo, short linkToIndex, CMultiCommand *command, bool bRecursive)
{
	ISceneNode *pNode = GetRoomFromHelper(pLinkFrom);

	vector3df euler1 = pLinkFrom->getAbsoluteTransformation().getRotationDegrees();
	vector3df euler2 = pLinkTo->getAbsoluteTransformation().getRotationDegrees();

	vector3df euler3 = euler1 - euler2;
	euler3.Z += 180;
	quaternion q(DEGTORAD * euler3);

	quaternion newRot = q * pNode->getRotation();

	CRotateCommand* rotate = new CRotateCommand(pNode->getID(), pNode->getRotation(), newRot);
	command->addCommand(rotate);

	//need this to update pLinkFrom absolute position after rotation
	core::vector3df rotateVec;
	newRot.toEuler(rotateVec);
	pNode->setRotation(rotateVec);
	pNode->updateAbsolutePosition();

	vector3df newPos = pNode->getPosition() + pLinkTo->getAbsolutePosition() - pLinkFrom->getAbsolutePosition();
	
	CMoveCommand* move = new CMoveCommand(pNode->getID(), pNode->getPosition(), newPos);
	command->addCommand(move);
	move->drop();
	rotate->drop();

	//need this to update pLinkFrom absolute position for recursivity
	pNode->setPosition(newPos);
	pNode->updateAbsolutePosition();

	CSceneObject *pObj = getSceneObjectFromID(pNode->getID());
	CSceneObject *pObj1 = getSceneObjectFromID(GetRoomFromHelper(pLinkTo)->getID());

	if (!bRecursive)
	{
		CLinkRoomCommand* link = new CLinkRoomCommand(pNode->getID(), GetRoomFromHelper(pLinkTo)->getID(), linkFromIndex, linkToIndex);
		command->addCommand(link);
		link->drop();
	}
	else
	{
		if (pObj->m_linkDoorID[linkFromIndex] != -1)
		{
			CSceneObject *pDoor = getSceneObjectFromID(pObj->m_linkDoorID[linkFromIndex]);
			vector3df oldPos = pDoor->m_SceneNode->getPosition();
			quaternion oldRot = pDoor->m_SceneNode->getRotation();
			matrix4 matAbsTransform = pLinkTo->getAbsoluteTransformation();
			if (pDoor->m_SceneNode->getParent())
			{
				matrix4 matParentAbsTransform = pDoor->m_SceneNode->getParent()->getAbsoluteTransformation();
				matParentAbsTransform.makeInverse();
				pDoor->m_SceneNode->setRelativeTransformation(matParentAbsTransform * matAbsTransform);
			}
			else
			{
				pDoor->m_SceneNode->setRelativeTransformation(matAbsTransform);
			}

			CRotateCommand* rotateDoor = new CRotateCommand(pDoor->m_SceneNode->getID(), oldRot, pDoor->m_SceneNode->getRotation());
			command->addCommand(rotateDoor);

			CMoveCommand* moveDoor = new CMoveCommand(pDoor->m_SceneNode->getID(), oldPos, pDoor->m_SceneNode->getPosition());
			command->addCommand(moveDoor);
			moveDoor->drop();
			rotateDoor->drop();
		}
	}

	for (int i=0; i < MAX_ROOM_LINKS; i++)
	{
		if (i == linkFromIndex) continue;

		if (pObj->m_roomIDLinks[i] == -1) continue;

		stringc name("LinkNode");
		name += pObj->m_linkIndexLinks[i];
		CSceneObject *pObj2 = getSceneObjectFromID(pObj->m_roomIDLinks[i]);
		ISceneNode *pFrom = GetLinkNodeFromName(pObj2->m_SceneNode, name);

		stringc name1("LinkNode");
		name1 += i;
		ISceneNode *pTo = GetLinkNodeFromName(pObj->m_SceneNode, name1);

		LinkRoomFromTo(pFrom, pObj->m_linkIndexLinks[i], pTo, i, command, true);
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
ISceneNode* CLevelEditor::GetLinkNodeFromName(ISceneNode *pStartNode, const stringc& name)
{
	core::list<ISceneNode*>::ConstIterator it = pStartNode->getChildren().begin();
	for (; it != pStartNode->getChildren().end(); ++it)
	{
		if (name == (*it)->getName())
		{
			return (*it);
		}
		
		ISceneNode *pNode = GetLinkNodeFromName((*it), name);

		if (pNode != NULL) return pNode;
	}

	return NULL;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::RecalculateCollisions()
{
	m_physicalWorld->Clear();

	for (int i=0; i < m_SceneObjects.size(); i++)
	{
		if (m_SceneObjects[i]->m_UserData->getAttributeAsString("!GameType") == "Collisions")
		{
			int roomId = GetRoomID(m_SceneObjects[i]->m_SceneNode);
			printf(" Room %d found " , roomId);

			CSceneObject *pObj = getSceneObjectFromID(roomId);

			printf(" Object %x  " , pObj);

			if (pObj)
			{
				m_physicalWorld->AddCollisionRoom(m_SceneObjects[i]->m_UserData->getAttributeAsString("MeshFile").c_str(), pObj->m_SceneNode->getAbsoluteTransformation());
			}
		}
	}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
void CLevelEditor::createTemplateNameInput()
{
	const dimension2d<u32> screen = g->driver->getScreenSize();

	IGUIWindow* pTemplateNameInputWindow = g->guienv->addWindow(
		rect<s32>((screen.Width - 165) >> 1, (screen.Height >> 1) - 50, 
		((screen.Width - 165) >> 1) + 165, (screen.Height >> 1) + 50), 
		true, L"Enter template name", 0, WND_ID_TEMPLATE_NAME);

	g->guienv->addEditBox(L"", rect<s32>(5, 45, 105, 65), true, pTemplateNameInputWindow, TEMPLATE_NAME_ID_EDIT_NAME_BOX);
	g->guienv->addButton(rect<s32>(110, 45, 160, 65), pTemplateNameInputWindow, TEMPLATE_NAME_ID_OK_BTN, L"OK");
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
void CLevelEditor::saveGameTemplates()
{
	IXMLWriter* xml = g->device->getFileSystem()->createXMLWriter((m_editorPath + "\\game_templates.xml").c_str());

	if (!xml)
		return;

	xml->writeXMLHeader();
	xml->writeLineBreak();

	for (u32 i = 0; i < m_GameTemplates.size(); i++)
	{
		xml->writeElement(L"object", false);
		xml->writeLineBreak();

		m_GameTemplates[i]->m_Attributes->write(xml);

		xml->writeClosingTag(L"object");
		xml->writeLineBreak();
		xml->writeLineBreak();
	}

	xml->drop();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
void CLevelEditor::UpdateEffects( u32 time )
{
	for (u32 i=0; i < m_Effects.size(); i++)
	{
		for (u32 j=0; j < m_Effects[i]->m_ParticleSystems.size(); j++)
		{
			//if (m_Effects[i]->m_ParticleSystems[j]->isVisible())
			{
				m_Effects[i]->m_ParticleSystems[j]->OnAnimate(time);
			}			
		}
	}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
void CLevelEditor::HideLods(ISceneNode* start)
{
	const char* startName = start->getName();
	stringw name(startName);
	name.make_lower();
	int index = name.find(L"_lod_0");
	if( index >= 0)
	{
		if ( (name.size() > (index + 6)) && name[index + 6] != '0' )
		{
			start->setVisible(false);
		}
	}

	ISceneNode* node = 0;

	const core::list<ISceneNode*>& list = start->getChildren();
	core::list<ISceneNode*>::ConstIterator it = list.begin();
	for (; it!=list.end(); ++it)
	{
		HideLods(*it);		
	}	
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
void CLevelEditor::showHideItems(const char* str)
{
	for (u32 z = 0; z < m_SceneObjects.size(); z ++)
	{
		if (m_SceneObjects[z]->m_UserData->getAttributeAsStringW("!GameType") == stringw(str) )
		{
			m_SceneObjects[z]->m_SceneNode->setVisible(!m_SceneObjects[z]->m_SceneNode->isVisible());
		}
	}	
}

void CLevelEditor::showHideItems(const char* str, bool show)
{
	for (u32 z = 0; z < m_SceneObjects.size(); z ++)
	{
		if (m_SceneObjects[z]->m_UserData->getAttributeAsStringW("!GameType") == stringw(str) )
		{
			m_SceneObjects[z]->m_SceneNode->setVisible(show);
			int id = m_SceneObjects[z]->m_SceneNode->getID();
			TreeNode * tree_node =ui->m_sceneGraphTree->FindNode(id);			
			tree_node->Checked = show;	
			ui->setSceneNodeVisible(id,show);
		}	
	}	
}

void CLevelEditor::switchSelAllCameras()
{
	static bool show = true;

	if(m_selection.size()==0)
		show = true;
	else
		setSelectedNode(0);

	if(!show)
	{
		show = !show;
		return;
	}

	for (u32 z = 0; z < m_SceneObjects.size(); z ++)
	{
		if (m_SceneObjects[z]->m_UserData->getAttributeAsStringW("!GameType") == stringw("CameraArea") )
		{			
			int id = m_SceneObjects[z]->m_SceneNode->getID();			
			toggleToSelection(getSceneObjectFromID(id)->m_SceneNode);			
		}	
		else if (m_SceneObjects[z]->m_UserData->getAttributeAsStringW("!GameType") == stringw("CamCtrlPoint") )
		{
			if(m_SceneObjects[z]->m_UserData->getAttributeAsInt("!^Owner^CameraArea")!=-1)
			{
				int id = m_SceneObjects[z]->m_SceneNode->getID();			
				toggleToSelection(getSceneObjectFromID(id)->m_SceneNode);
			}
		}
	}

	show = !show;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CLevelEditor::OnOffPlayCinematic(bool on, bool fromCurrentAndPause)
{
	if(on)
	{
		bool valid = ui->m_CinematicEditor.InitPreviewData();
		if(!valid)
		{
			g->guienv->addMessageBox(L"Error!", L"The cinematic can't be played as a movie!", true);
			return;
		}

		CCinematicCameraAnimator* anim = (CCinematicCameraAnimator*)*g->camera[CINEMATIC_CAMERA]->getAnimators().begin();
		anim->setCameraThread(ui->m_CinematicEditor.m_cameraThread);
		g->setActiveCamera(CINEMATIC_CAMERA);	

		g->OnOffDeviceEmulatorMode(true);
		m_isPlayingCinematic = true;
		m_isPlayingCinematicEnd = false;
		m_isCinematicPause = false;
		m_isCinematicStepOneFrame = false;

		m_cnm_currentTime = 0;		
		m_cnm_lastTime = -1;	

		if(fromCurrentAndPause)
		{
			int nowTime = ui->m_CinematicEditor.GetNowTime();
			PlayCinematicToTime(nowTime);
			PausePlayCinematic();
		}
	}
	else
	{
		g->setActiveCamera(MAYA_CAMERA);
		g->OnOffDeviceEmulatorMode(false);		
		m_isPlayingCinematic = false;
		m_isCinematicPause = false;
		m_isCinematicStepOneFrame = false;
		m_cnm_objUpdateList.clear();
	}
}

void CLevelEditor::PausePlayCinematic()
{
	m_isCinematicPause = !m_isCinematicPause;
}

void CLevelEditor::StepPlayCinematic()
{
	if(m_isCinematicPause)
		m_isCinematicStepOneFrame = true;
}

bool CLevelEditor::execCmds(CCinematicThread* thread, int currentTime, bool backgroundRun)
{
	int keyFrameNum = thread->m_ThreadCinematics->size();

	//DEBUG_OUT("currentTime=%d\n",currentTime);

	int start = thread->m_lastExecdCmd+1;

	for(int i=start; i<keyFrameNum; i++)
	{
		CCinematicCommand* cmd = (*thread->m_ThreadCinematics)[i];		
				
		if(cmd->m_time>currentTime)
		{
			break;
		}
		else if (cmd->m_time <= currentTime)
		{
			//DEBUG_OUT("exec cmd %d, %s, time=%d\n",i,core::stringc(cmd->m_Name.c_str()).c_str(), cmd->m_time);

			if(cmd->m_Name=="SetVisible")
			{		
				CSceneObject* pObj = thread->m_Obj;
				if(pObj==0)
				{
					int objID = cmd->m_Attributes->getAttributeAsInt("ObjectID");
					if(objID>=0)
					{
						pObj = getSceneObjectFromID(objID);
					}
				}
					
				if(pObj!=0)
				{
					bool visible = cmd->m_Attributes->getAttributeAsBool("Visible");
					pObj->m_SceneNode->setVisible(visible);
				}								
			}
			else if(cmd->m_Name=="SetAnim")
			{
				
				array<stringw> animNames = thread->m_Obj->GetAnimationNames();
				core::stringc name = cmd->m_Attributes->getAttributeAsString("$Anim");
				int animID = animNames.linear_search(name.c_str())-1;
				if(animID>=0)
				{
					bool loop = cmd->m_Attributes->getAttributeAsBool("loop");
					float speed = cmd->m_Attributes->getAttributeAsFloat("speed");
					//thread->m_Obj->SetAnimWithSpeed(animID, speed, loop);
				}				
			}
			else if(cmd->m_Name=="PlayEffect")
			{
				int dummyObjID = cmd->m_Attributes->getAttributeAsInt("^dummy object");
				if(dummyObjID>=0)
				{
					CSceneObject* pObj = getSceneObjectFromID(dummyObjID);
					irr::core::vector3df pos = cmd->m_Attributes->getAttributeAsVector3d("pos");
					if(pos!=irr::core::vector3df(0,0,0))
					{
						pObj->m_SceneNode->setPosition(pos);
						pObj->m_SceneNode->updateAbsolutePosition();
					}
					pObj->m_SceneNode->setVisible(true);
					const irr::core::stringw& effectType = cmd->m_Attributes->getAttributeAsStringW("$EffectType");
					SetObjectEffectType(pObj->m_SceneNode, effectType);
					bool inserted = false;
					for(int idx=0; idx<m_cnm_objUpdateList.size(); ++idx)
					{
						if(m_cnm_objUpdateList[idx]==pObj)
						{
							inserted = true;
							break;
						}
					}
					if(!inserted)
						m_cnm_objUpdateList.push_back(pObj);
				}
			}

			thread->m_lastExecdCmd = i;			
		}				
	}

	return (thread->m_lastExecdCmd==keyFrameNum-1);		
}

bool CLevelEditor::execInterpCmd(CCinematicThread* thread, int currentTime, const stringw& cmdName, int& lastExecKey)
{
	bool bEnd = false;
	int key1=-1, key2=-1;

	int keyFrameNum = thread->m_ThreadCinematics->size();

	int savelastKey = lastExecKey;
		
	key1=lastExecKey, key2=lastExecKey+1;

	for(int i=lastExecKey+1; i<keyFrameNum; i++)
	{
		CCinematicCommand* cmd = (*thread->m_ThreadCinematics)[i];
		//DEBUG_OUT("key%d, time=%d\n",i,cmd->m_time);
		if( cmd->m_Name == cmdName)
		{
			if (cmd->m_time <= currentTime)
			{
				key1 = i;
				lastExecKey = i;
				break;
			}
		}
	}	

	key2 = -1;
	for(int k2 = key1+1; k2<keyFrameNum; k2++)
	{
		CCinematicCommand* cmd = (*thread->m_ThreadCinematics)[k2];		
		if( cmd->m_Name == cmdName)
		{
			key2 = k2;
			break;
		}
	}
	
	if(key2==-1)//not found next key, set to same key
	{
		bEnd = true;
		key2 = key1;
	}

	if(key1>=0 && key2>=0)
	{
		if(cmdName=="MoveObject")
		{
			//DEBUG_OUT("MoveObject key1=%d, key2=%d\n",key1,key2);
			if(key1==key2)
			{
				CCinematicCommand* cmd = (*thread->m_ThreadCinematics)[key1];
				irr::core::vector3df pos = cmd->m_Attributes->getAttributeAsVector3d("pos");
				irr::core::quaternion rot = cmd->m_Attributes->getAttributeAsQuaternion("rot");
				thread->m_Obj->m_SceneNode->setPosition(pos);
				core::vector3df rotate;
				rot.toEuler(rotate);
				thread->m_Obj->m_SceneNode->setRotation(rotate);				
			}
			else
			{
				int dtime = (*thread->m_ThreadCinematics)[key2]->m_time - (*thread->m_ThreadCinematics)[key1]->m_time;
				float percent = (currentTime-(*thread->m_ThreadCinematics)[key1]->m_time)/(float)dtime;
				if(dtime<=EVENTS_INTERVAL)
					percent=0;

				CCinematicCommand* cmd1 = (*thread->m_ThreadCinematics)[key1];
				irr::core::vector3df pos1 = cmd1->m_Attributes->getAttributeAsVector3d("pos");
				irr::core::quaternion rot1 = cmd1->m_Attributes->getAttributeAsQuaternion("rot");

				CCinematicCommand* cmd2 = (*thread->m_ThreadCinematics)[key2];
				irr::core::vector3df pos2 = cmd2->m_Attributes->getAttributeAsVector3d("pos");
				irr::core::quaternion rot2 = cmd2->m_Attributes->getAttributeAsQuaternion("rot");

				irr::core::vector3df pos = pos1+(pos2-pos1)*percent;
				irr::core::quaternion rot;
				rot.slerp(rot1,rot2,percent);
				thread->m_Obj->m_SceneNode->setPosition(pos);
				core::vector3df rotate;
				rot.toEuler(rotate);
				thread->m_Obj->m_SceneNode->setRotation(rotate);					
			}
		}	
	}
	return bEnd;
}

void CLevelEditor::PlayCinematicToTime(int destTime)
{
	bool valid = ui->m_CinematicEditor.InitPreviewData();
	if(!valid)
	{		
		return;
	}
						
	m_cnm_currentTime = 0;		
	m_cnm_lastTime = -1;

	int playTime = 0;
	while(true)
	{
		PlayCinematic(playTime, true);

		CCinematicCameraAnimator* cameraAnim = (CCinematicCameraAnimator*)*g->camera[CINEMATIC_CAMERA]->getAnimators().begin();
		cameraAnim->update(playTime);

		playTime+=50;
		if(playTime>destTime)
			break;		
	}
}

void CLevelEditor::PlayCinematic(int timeMs, bool backgroundRun)
{
	if(!backgroundRun && m_isCinematicPause && !m_isCinematicStepOneFrame)
	{			
		return;	
	}

	array<CCinematicThread*> &threads = ui->m_CinematicEditor.m_objThreads;

	int dt = 0;
	if(m_cnm_lastTime>=0)
		dt = timeMs-m_cnm_lastTime;
	else
		dt = 50;
	m_cnm_lastTime = timeMs;


	if(!backgroundRun && m_isCinematicStepOneFrame)
	{
		dt = 50;
		m_isCinematicStepOneFrame = false;
	}

	if(dt==0)
		return;
	else if(dt>500)//maybe return from pause, cause a big dt
		dt = 50;
	

	//DEBUG_OUT("timeMs=%d, m_cnm_currentTime=%d, dt=%d\n",timeMs,m_cnm_currentTime,dt);

	bool bEnd = true;
	int threadsNum = threads.size();
	for(int t=0; t<threadsNum; ++t)
	{
		CCinematicThread* thread = threads[t];
		
		execInterpCmd(thread, m_cnm_currentTime, "MoveObject", thread->m_lastExecdKeyFrame);				
		
		bEnd &= execCmds(thread, m_cnm_currentTime, backgroundRun);			
	}

	CCinematicCameraAnimator* cameraAnim = (CCinematicCameraAnimator*)*g->camera[CINEMATIC_CAMERA]->getAnimators().begin();
	//cameraAnim->update(m_cnm_currentTime);

	for(int i=0; i<m_cnm_objUpdateList.size(); ++i)
	{
		m_cnm_objUpdateList[i]->m_SceneNode->OnAnimate(m_cnm_currentTime);
		//m_cnm_objUpdateList[i]->UpdateAnim(dt);
	}

	//if all threads end, restore some state
	if(bEnd)
	{
		for(int t=0; t<threadsNum; ++t)
		{
			CCinematicThread* thread = threads[t];
			if(thread->m_Obj!=0)
				thread->m_Obj->m_SceneNode->setVisible(thread->m_visibleInScene);
		}
	}

	m_cnm_currentTime+= dt;

	if(backgroundRun)
		return;

	if( bEnd )
	{		
		bEnd = cameraAnim->isFinished();		
	}	

	if( bEnd)
	{
		OnOffPlayCinematic(false);
	}
}



void CLevelEditor::OnOffCamCtrlPointSetOffset(bool on, CSceneObject* pCamCtrlPoint)
{
	if(on)
	{
		if(pCamCtrlPoint!=0)
		{
			m_savedCamCtrlPointPos = pCamCtrlPoint->m_SceneNode->getPosition();
			irr::core::vector3df offset;
			offset.X = pCamCtrlPoint->m_UserData->getAttributeAsFloat("targetOffsetX");
			offset.Y = pCamCtrlPoint->m_UserData->getAttributeAsFloat("targetOffsetY");
			offset.Z = pCamCtrlPoint->m_UserData->getAttributeAsFloat("targetOffsetZ");
			pCamCtrlPoint->m_SceneNode->setPosition(m_savedCamCtrlPointPos+offset);

			pCamCtrlPoint->m_UserData->setAttribute("targetOffsetX",0);
			pCamCtrlPoint->m_UserData->setAttribute("targetOffsetY",0);
			pCamCtrlPoint->m_UserData->setAttribute("targetOffsetZ",0);

			ui->m_MovePushButton->setPressed(true);
			updateControls();
		}
	}
	else
	{
		if(pCamCtrlPoint!=0)
		{
			ui->m_MovePushButton->setPressed(false);
			updateControls();

			irr::core::vector3df offset = pCamCtrlPoint->m_SceneNode->getPosition()-m_savedCamCtrlPointPos;
			pCamCtrlPoint->m_UserData->setAttribute("targetOffsetX",offset.X);
			pCamCtrlPoint->m_UserData->setAttribute("targetOffsetY",offset.Y);
			pCamCtrlPoint->m_UserData->setAttribute("targetOffsetZ",offset.Z);
			pCamCtrlPoint->m_SceneNode->setPosition(m_savedCamCtrlPointPos);
			
			editor->AddCommand(new CMoveCommand(pCamCtrlPoint->m_SceneNode->getID(), pCamCtrlPoint->m_SceneNode->getPosition(), m_savedCamCtrlPointPos));

			ui->updateProperties();
		}
	}
}

void CLevelEditor::SnapCamCtrlPointTargetToEdge(CSceneObject* pCamCtrlPoint)
{
	if(pCamCtrlPoint!=0)
	{
		CameraArea ca;
		ca.InitFromOneOfContrlPointObj(pCamCtrlPoint);
		ca.SnapTargetOffsetToNearEdge();
		ui->updateProperties();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
